Java - remove last known item from HASHMAP on MAP!s - java

OK so this is a BIT different. I have a new HashMap
private Map<String, Player> players = new HashMap<String, Player>();
How do I remove last known item from that? Maybe somethign like this?
hey = Player.get(players.size() - 1);
Player.remove(hey);

The problem is, a HashMap is not sorted like a list. The internal order depends on the hashCode() value of the key (e.g. String). You can use a LinkedHashMap which preserves the insert order. To remove the last entry on this you can use an iterator in combination with a counter which compares to the size and remove the last entry.
It's so easy. Try this:
Map<String, Player> players = new LinkedHashMap<String, Players>();
List<String> list = new ArrayList<String>(players.keySet());
map.remove(list.get(list.size()-1));

I'm a little bit confused. First of all, you're saying that you've got a new ArrayList and you're illustrating this with a line that creates a new HashMap. Secondly, does the Player class really have static methods like get(int) and remove(Object)?
HashMap doesn't have a particular order, ArrayList (as any other List) does.
Removing from an ArrayList
If you've got a list of players, then you can do the following:
private List<Player> players = new ArrayList<Player>();
// Populate the list of players
players.remove(players.size() - 1);
Here, I've used the remove(int) method of List, which allows to remove an item at an arbitrary index.
Removing from a HashMap
If you've got a map of players, there's no such thing as "the last item". Sure, you can iterate over the map and one of the items will pop out last, but that doesn't mean anything. Therefore, first you have to find out what you want to remove. Then you can do the following:
private Map<String, Player> players = new HashMap<String, Player>();
// Populate the map of players
// Find the key of the player to remove
players.remove(toRemove);
Here, I've used the remove(Object) method of Map. Note that in order to remove some key-value pair, you have to show the key, not the value.

There's no "first" and "last" in a HashMap. It's unordered. Everything is accessible by its key, not by index.

You cannot delete from HashMap like that. You need to use LinkedHashMap.

Simple, just do something of this effect.
1) Get a keyset iterator;
2) Create a Key somelastKey = null
3) Iterate through the iterator and assigning somelastKey until iterator finishes.
4) finally, do players.remove(somelastKey);
Bear in mind that HashMap is unordered, it depends on Object's hashCode to determine insertion order.
Instead of using HashMap, try using LinkedHashMap which keeps a predictable iteration order.
Hope this helps....

You'll probably have to extend HashMap, override put so that it caches the key, and then create a new method that just removes the key that was cached.
Unfortunately, this will only let you remove the most recently added. If you need to remove the most recently added multiple times (without inserting in-between the removes), you're out of luck.
In that case, I'd probably do the same overrides, just write the keys to a List. So you'd have both a list and a Map.

When adding:
String key; Player value;
lastKey = key;
map.put(key, value);
//...later...
Player lastAdded = map.remove(lastKey);
Other than that there's really no way without using a LinkedHashMap or in some way creating your own wrapper map or extending HashMap.

You shouldn't be using a raw hashmap anywhere because things like this happen.
Get in the habit of wrapping your collections in business logic classes.
See, in your case right now you need to associate these two related variables--your hashmap and a "Last entered" item so you can remove it.
If you need to remove the last item from some other class, you need to pass both items.
Any time you find yourself passing 2 or more items together into more than one API, you are probably missing a class.
Create a new class that contains the hashmap and a "lastAdded" variable. Have put and remove methods that are just forwarded to the hashmap, but the put method would also set the lastAdded variable.
Also be sure to add a removeLast() method.
NEVER allow access to your hashmap outside this class, it needs to be completely private (this is what I mean by wrapped). In this way you can ensure it doesn't get out of sync with the lastAdded variable (also completely private).
Just to reiterate getters and setters for these variables would be a terrible idea (as they are with nearly all actual OO code).
You will quickly find a bunch of other methods that NEED to be in this class in order to access data inside your hashmap--methods that never felt right in their current location. You will probably also notice that those methods always have an additional parameter or two passed in--those parameters should probably be members of your new class.
Once you get in the habit of doing actual OO design (via refactoring in this case), you'll find your code MUCH more manageable. To illustrate this point, if you find later that you need multiple levels of "delete last", it will be TRIVIAL to add to your class because it will be extremely clear exactly what methods can modify your hashtable and where your new "stack" of lastItems should be located--in fact it's probably a 2 line code change.
If you do not make this wrapper class, various locations will each have code to set "lastAdded" when they add code to the hashtable. Each of those locations will have to be modified, some may be in other classes requiring you to pass your new stack around with the hashtable. It will be easier to get them out of synch if you forget to change one location.

Related

Random access for HashMap keys

I need to randomly access keys in a HashMap. Right now, I am using Set's toArray() method on the Set that HashMap's keySet() returns, and casting it as a String[] (my keys are Strings). Then I use Random to pick a random element of the String array.
public String randomKey() {
String[] keys = (String[]) myHashMap.keySet().toArray();
Random rand = new Random();
return keyring[rand.nextInt(keyring.length)];
}
It seems like there ought to be a more elegant way of doing this!
I've read the following post, but it seems even more convoluted than the way I'm doing it. If the following solution is the better, why is that so?Selecting random key and value sets from a Map in Java
There is no facility in a HashMap to return an entry without knowing the key so, if you want to use only that class, what you have is probably as good a solution as any.
Keep in mind however that you're not actually restricted to using a HashMap.
If you're going to be reading this collection far more often than writing it, you can create your own class which contains both a HashMap of the mappings and a different collection of the keys that allows random access (like a Vector).
That way, you won't incur the cost of converting the map to a set then an array every time you read, it will only happen when necessary (adding or deleting items from your collection).
Unfortunately, a Vector allows multiple keys of the same value so you would have to defend against that when inserting (to ensure fairness when selecting a random key). That will increase the cost of insertion.
Deletion would also be increased cost since you would have to search for the item to remove from the vector.
I'm not sure there's an easy single collection for this purpose. If you wanted to go the whole hog, you could have your current HashMap, a Vector of the keys, and yet another HashMap mapping the keys to the vector indexes.
That way, all operations (insert, delete, change, get-random) would be O(1) in time, very efficient in terms of time, perhaps less so in terms of space :-)
Or there's a halfway solution that still uses a wrapper but creates a long-lived array of strings whenever you insert, change or delete a key. That way, you only create the array when needed and you still amortise the costs. Your class then uses the hashmap for efficient access with a key, and the array for random selection.
And the change there is minimal. You already have the code for creating the array, you just have to create your wrapper class which provides whatever you need from a HashMap (and simply passes most calls through to the HashMap) plus one extra function to get a random key (using the array).
Now, I'd only consider using those methods if performance is actually a problem though. You can spend untold hours making your code faster in ways that don't matter :-)
If what you have is fast enough, it's fine.
Why not use the Collections.shuffle method, saved to a variable and simply pop one off the top as required.
http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#shuffle(java.util.List)
You could avoid copying the whole keyset into a temporary data structure, by first getting the size, choosing the random index and then iterating over the keyset the appropriate number of times.
This code would need to be synchronized to avoid concurrent modifications.
If you really just want any element of a set, this will work fine.
String s = set.iterator().next();
If you are unsure whether there is an element in the set, use:
String s;
Iterator<String> it = set.iterator();
if (it.hasNext()) {
s = it.next();
}
else {
// set was empty
}

Why does java.util.Map.values() allow you to remove entries from the returned Collection

Why does java.util.Map.values() allow you to delete entries from the returned Collection when it makes no sense to remove a key value pair based on the value? The code which does this would have no idea what key the value(and hence a key) being removed is mapped from. Especially when there are duplicate values, calling remove on that Collection would result in an unexpected key being removed.
it makes no sense to remove a key value pair based on the value
I don't think you're being imaginative enough. I'll admit there probably isn't wide use for it, but there will be valid cases where it would be useful.
As a sample use case, say you had a Map<Person, TelephoneNumber> called contactList. Now you want to filter your contact list by those that are local.
To accomplish this, you could make a copy of the map, localContacts = new HashMap<>(contactList) and remove all mappings where the TelephoneNumber starts with an area code other than your local area code. This would be a valid time where you want to iterate through the values collection and remove some of the values:
Map<Person, TelephoneNumber> contactList = getContactList();
Map<Person, TelephoneNumber> localContacts = new HashMap<Person, TelephoneNumber>(contactList);
for ( Iterator<TelephoneNumber> valuesIt = localContacts.values().iterator(); valuesIt.hasNext(); ){
TelephoneNumber number = valuesIt.next();
if ( !number.getAreaCode().equals(myAreaCode) ) {
valuesIt.remove();
}
}
Especially when there are duplicate values, calling remove on that Collection would result in an unexpected key being removed.
What if you wanted to remove all mappings with that value?
It has to have a remove method because that's part of Collection. Given that, it has the choice of allowing you to remove values or throwing an UnsupportedOperationException. Since there are legitimate reasons that you might want to remove values, why not choose to allow this operation?
Maybe there's a given value where you want to remove every instance
of it from the Map.
Maybe you want to trim out every third
key/value pair for some reason.
Maybe you have a map from hotel
room number to occupancy count and you want to remove everything from
the map where the occupancy count is greater than one in order to
find a room for someone to stay in.
...if you think about it more
closely, there are plenty more examples like this...
In short: there are plenty of situations where this might be useful and implementing it doesn't harm anyone who doesn't use it, so why not?
I think there is quite often a use for removing a value based on a key; other answers show examples. Given that, if you want to remove a certain value, why would you only want one particular key of it removed? Even if you did, you'd have to know which key you wanted to remove (or not, as the case may be), and then you should just remove it by key anyway.
The Collection returned is a special Collection, and its semantics are such that it knows how values in it relate back to the Map it came from. The javadoc indicates what Collection operation the returned collection supports.

Creating a custom iterator for a HashMap

I am trying to implement an iterator that will iterate through the HashMap and its duplicates. For example string.put("a", 1);
string.put("a", 2);
string.put("b", 3);
string.put("b", 4);
However with my iterator I only iterate twice, once for where the value is "a" and the other for "b". I'd like to make an iterator that will iterate 4 times throughout the whole Map.
EDIT: I kind of left out a lot of detail because I just wanted to see if this iterator was possible, but the code I'm writing is actually an abstraction of a map. For example, I have an add function which takes in parameter T. So for adding a string it would look like add("Hello"). By adding this string, it's key is "String" and its value is 1. If I call add("Hello") again it will bump up the value to 2. If I add it again, it will bump up its value to 3 and so on. I want to create an iterator that will iterate through all the stuff I have added.
Unfortunately, Java's Map interface doesn't allow for duplicate keys:
An object that maps keys to values. A
map cannot contain duplicate keys;
each key can map to at most one value.
Thus, when you try to put a key that already exists in the map, the new value replaces the old value; the reason your iterator iterates 2 times is because there are only 2 items.
If you want to keep duplicate keys (like "a" pointing to both 1 and 2), either you can have a Map of a List or Set, like
Map<String, List<Integer>> myMap;
Where the list or set that a key maps to contains all values, like myMap.get("a") would return a list that would look like [1,2].
Or use something like a MultiMap from either Google or Apache
For your problem, I believe you are saying that you want a special Map where:
The value for each key to be how many times the key was entered.
When you iterate over the map, you iterate over all the keys you added, for each time they were added.
You may want to look at how they implemented iterator() for HashMap, specifically looking at the internal private class HashIterator.
next() and hasNext() could maybe keep returning the key for as many times as specified by the value (i.e. if "Hello" maps to 2, your custom iterator() will return with next() "Hello" two times before moving onto the next key).
Map may not be an appropriate structure to use for what you're trying to do, but I wish you luck!
You can try using a Multimap from the guava library. java.util.HashMap allows to associate only one value with one key.
You can access an Iterator for your HashMap like this :
myHashMap.entrySet.iterator()
If you want to loop on all your objects, this is a faster way :
for(Object o : myHashMap.entrySet()) {
// do something with o
}
The problem in your case seems to come from the fact that a HashMap in java can't have identical keys, so your code add only two objects to the HashMap.

HashMap inside an Arraylist

ArrayList<HashMap<String, String>>
arrayListRowsFirst = new ArrayList<HashMap<String, String>>();
Today when i was going through a code, this piece of code struck me for a while. Here are some of my questions over this declaration.
What could be the requirement if one has to append an HashMap into an ArrayList.
What will happen during sorting of arraylist, how it will go, will it take long time.
First off, "generic chaining" in my opinion is a poor practice. I would encourage wrapping the HashMap in a class that encapsulates the data inside, allowing the logic for manipulation to be inside the class, not just strewn about everywhere.
To answer #1, I could think of a number of scenarios. You might have languages for instance, mapping certain constants to other translations. The fact that it says rows first in the identifier makes me think perhaps it's some kind of matrix of data, and that the first String parameter will exist in all the entries of the list (a poor practice indeed.)
Edit: I misunderstood your question, it appears. You would add it like any other entry. See the others' answers for example code. :-)
To answer #2, you won't be able to sort the ArrayList unless you are able to provide a comparator, at which point it's up to you how it's sorted (could be size, could be the value of a particular key, could be Math.random(), it's up to whoever writes the comparator).
There is no "special requirement" to append an HashMap to an ArrayList.
And as neither Map nor HashMap implements Comparable, so if you want to sort the ArrayList, you would have to create your own Comparator.
A sort on a List which contains Map would be exactly the same as a sort on a List wich contains anything else.
What do you mean about "append a HashMap into an ArrayList"? You add HashMaps to the ArrayList the way you add any object to a List
HashMap<String,String> hm = new HashMap<String,String>();
arrayListRowsFirst.add(hm);
You sort the array list like you sort any other - you would need to define a Comparator that compared two HashMaps, and use Collections.sort with that Comparator. How long it takes will depend a lot on how you're comparing the HashMaps.
You would add HashMaps to the ArrayList like you would any other object, using the add() method. Obviously it would need to be of the correct Type, in this case a HashMap of Strings.
You would need to create a comparator so that your HashMaps would be sortable.
The declaration should be
List<Map<String, String>>
1 to append a map into the list, you just do
Map<String, String> map = new HashMap<String, String>();
list.add(map);
2 To sort the list, you would need a way to tell if one Map is "greater than", "less than", or "equal" to another Map. The could or might not take a long time depending on your needs. It doesn't have to take a long time.

Difference between HashMap and ArrayList in Java?

In Java, ArrayList and HashMap are used as collections. But I couldn't understand in which situations we should use ArrayList and which times to use HashMap. What is the major difference between both of them?
You are asking specifically about ArrayList and HashMap, but I think to fully understand what is going on you have to understand the Collections framework. So an ArrayList implements the List interface and a HashMap implements the Map interface. So the real question is when do you want to use a List and when do you want to use a Map. This is where the Java API documentation helps a lot.
List:
An ordered collection (also known as a
sequence). The user of this interface
has precise control over where in the
list each element is inserted. The
user can access elements by their
integer index (position in the list),
and search for elements in the list.
Map:
An object that maps keys to values. A
map cannot contain duplicate keys;
each key can map to at most one value.
So as other answers have discussed, the list interface (ArrayList) is an ordered collection of objects that you access using an index, much like an array (well in the case of ArrayList, as the name suggests, it is just an array in the background, but a lot of the details of dealing with the array are handled for you). You would use an ArrayList when you want to keep things in sorted order (the order they are added, or indeed the position within the list that you specify when you add the object).
A Map on the other hand takes one object and uses that as a key (index) to another object (the value). So lets say you have objects which have unique IDs, and you know you are going to want to access these objects by ID at some point, the Map will make this very easy on you (and quicker/more efficient). The HashMap implementation uses the hash value of the key object to locate where it is stored, so there is no guarentee of the order of the values anymore. There are however other classes in the Java API that can provide this, e.g. LinkedHashMap, which as well as using a hash table to store the key/value pairs, also maintains a List (LinkedList) of the keys in the order they were added, so you can always access the items again in the order they were added (if needed).
If you use an ArrayList, you have to access the elements with an index (int type). With a HashMap, you can access them by an index of another type (for example, a String)
HashMap<String, Book> books = new HashMap<String, Book>();
// String is the type of the index (the key)
// and Book is the type of the elements (the values)
// Like with an arraylist: ArrayList<Book> books = ...;
// Now you have to store the elements with a string key:
books.put("Harry Potter III", new Book("JK Rownling", 456, "Harry Potter"));
// Now you can access the elements by using a String index
Book book = books.get("Harry Potter III");
This is impossible (or much more difficult) with an ArrayList. The only good way to access elements in an ArrayList is by getting the elements by their index-number.
So, this means that with a HashMap you can use every type of key you want.
Another helpful example is in a game: you have a set of images, and you want to flip them. So, you write a image-flip method, and then store the flipped results:
HashMap<BufferedImage, BufferedImage> flipped = new HashMap<BufferedImage, BufferedImage>();
BufferedImage player = ...; // On this image the player walks to the left.
BufferedImage flippedPlayer = flip(player); // On this image the player walks to the right.
flipped.put(player, flippedPlayer);
// Now you can access the flipped instance by doing this:
flipped.get(player);
You flipped player once, and then store it. You can access a BufferedImage with a BufferedImage as key-type for the HashMap.
I hope you understand my second example.
Not really a Java specific question. It seems you need a "primer" on data structures. Try googling "What data structure should you use"
Try this link http://www.devx.com/tips/Tip/14639
From the link :
Following are some tips for matching the most commonly used data structures with particular needs.
When to use a Hashtable?
A hashtable, or similar data structures, are good candidates if the stored data is to be accessed in the form of key-value pairs. For instance, if you were fetching the name of an employee, the result can be returned in the form of a hashtable as a (name, value) pair. However, if you were to return names of multiple employees, returning a hashtable directly would not be a good idea. Remember that the keys have to be unique or your previous value(s) will get overwritten.
When to use a List or Vector?
This is a good option when you desire sequential or even random access. Also, if data size is unknown initially, and/or is going to grow dynamically, it would be appropriate to use a List or Vector. For instance, to store the results of a JDBC ResultSet, you can use the java.util.LinkedList. Whereas, if you are looking for a resizable array, use the java.util.ArrayList class.
When to use Arrays?
Never underestimate arrays. Most of the time, when we have to use a list of objects, we tend to think about using vectors or lists. However, if the size of collection is already known and is not going to change, an array can be considered as the potential data structure. It's faster to access elements of an array than a vector or a list. That's obvious, because all you need is an index. There's no overhead of an additional get method call.
4.Combinations
Sometimes, it may be best to use a combination of the above approaches. For example, you could use a list of hashtables to suit a particular need.
Set Classes
And from JDK 1.2 onwards, you also have set classes like java.util.TreeSet, which is useful for sorted sets that do not have duplicates. One of the best things about these classes is they all abide by certain interface so that you don't really have to worry about the specifics. For e.g., take a look at the following code.
// ...
List list = new ArrayList();
list.add(
Use a list for an ordered collection of just values. For example, you might have a list of files to process.
Use a map for a (usually unordered) mapping from key to value. For example, you might have a map from a user ID to the details of that user, so you can efficiently find the details given just the ID. (You could implement the Map interface by just storing a list of keys and a list of values, but generally there'll be a more efficient implementation - HashMap uses a hash table internally to get amortised O(1) key lookup, for example.)
A Map vs a List.
In a Map, you have key/value pairs. To access a value you need to know the key. There is a relationship that exists between the key and the value that persists and is not arbitrary. They are related somehow. Example: A persons DNA is unique (the key) and a persons name (the value) or a persons SSN (the key) and a persons name (the value) there is a strong relationship.
In a List, all you have are values (a persons name), and to access it you need to know its position in the list (index) to access it. But there is no permanent relationship between the position of the value in the list and its index, it is arbitrary.

Categories