How can i get the last and first key/value of a Map?
For example:
Map<String,Integer> ret = new HashMap<String,Integer>();
And this is ret's value:
{33=1, 12=2, 21=2, 93=2, 48=9, 68=10}
You cannot do it with HashMap because keys are not ordered. Consider using LinkedHashMap
You can get last element using this method:
public <K,V> Map.Entry<K,V> getLast(LinkedHashMap<K,V> map) {
Iterator<Map.Entry<K,V>> iterator = map.entrySet().iterator();
Map.Entry<K, V> result = null;
while (iterator.hasNext()) {
result = iterator.next();
}
return result;
}
A HashMap is an unordered map, so it doesn't have any concept of 'first' or 'last.
If you want a map that retains things in insertion order, you can use a LinkedHashMap, and then iterate its entrySet() method to pick the first and last values.
You could also use the SortedMap interface (TreeMap impl.) which orders inserted entries by the natural ordering of keys (or a provided Comparator).
It isn't possible (or more like doesn't make sense) to differentiate between "first" and "last" when it comes to HashMap. If you want to preserve insertion order, you might want to use LinkedHashMap<K,V>. But then again, you should elaborate your question to let us know the exact use case demanding this.
since there is no defined order you will basically get a random element if you are unlucky.
else you could go the way HashMap -> getEntrySet -> toArray -> get(size-1)
Technically, you can get the first object from the map via:
Map.Entry<Integer,Integer> entry = map.entrySet().iterator().next();
And the last via:
Iterator<Map.Entry<Integer,Integer>> iter = map.entrySet().iterator();
Map.Entry<Integer,Integer> entry = null;
while(iter.hasNext()) {
entry = iter.next();
}
// now you have the "last" item in the map stored in 'entry'
But, as has been stated in other answers, this doesn't mean anything with a HashMap. Substitute it with a LinkedHashMap, however, and you can get the first and last inserted pairs out using the above code.
Unless you use a http://docs.oracle.com/javase/6/docs/api/java/util/SortedMap.html, in which case you could get the first and last key..
Related
I'm having problems on how to tackle this since I know a map has no specific order. I would think that you would iterate over the map's Keys and then check the value count by getting the size of the LinkedList since the Values to the Key are held in a LinkedList I can just call a size or length call for the LinkedList, but my main question is how to get inside the HashMap with an iterator first to do this?
An iterator over all the entries of a map can be done as follows in Java:
for (Map.Entry<Key, Value> entry : map.entrySet()) {
Key k = entry.getKey();
Value v = entry.getValue();
// do something with k,v
}
However, a map can only contain at most one value associated with a key. So, if using a map of lists to associate multiple values, the list would be accessed simply through get.
I suppose you have something like this :
Map<Integer,List<Integer>> map = new HashMap<>();
You can just iterate very simply through all the values you have.
for (List<Integer> values : map.values()){
System.out.println(values.size());
}
I have Map in Java
Map<String, List<String>> Collections;
String - a parents to ExpandtableList
List -a children to Expandtable List
Example Values
<"12" , "5,6,7,8">
<"15" , "4,6,2,8">
<"17" , "1,6,7,8">
<"8" , "5,6,6,8">
I'd like to get second parent and atribute to temporary String variable.(it is a "17") How can i refer to 2-nd parent and return value ?
There is no ordering in HashMap. If you want to focused on Order with Map you should use LinkedHashMap.
Use LinkedHashMap instead of HashSet. LinkedHashMap will maintain the insertion order.
Well, if you want "17" then you can just write map.get("17") to get the List.
Java doesnt keep track of the order here as it uses a Set to store the data. map.keySet() will return you a set you can iterate through.
You can HOPE that 17 falls under the natural ordering that Java does and do something like this.
HashMap<String, List<String>> map = new HashMap<>();
int count = 0;
for (String key : map.keySet()) {
count++;
if (count == 2)
return map.get(key);
}
If you want to retain an order in a Map, your usual choice would be a LinkedHashMap. With a linked hash map, you do however still not have direct access to an entry by its index. You would need to write a helper function:
static List<String> indexList(LinkedHashMap<String, List<String>> map, int index) {
int i = 0;
for(Map.Entry<String, List<String>> entry : map.entrySet()) {
if(i++ == index) {
return entry.getValue();
}
}
throw new IndexOutOfBoundException();
}
When using maps that point to a list, you might also be interested in using Guava's Multimap.
I have created a HashMap as per my code...
HashMap map=new HashMap();//HashMap key random order.
map.put("Amit","Java");
map.put("Saral","J2EE");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
System.out.println("There are "+map.size()+" elements in the map.");
System.out.println("Content of Map are...");
Set s=map.entrySet();
Iterator itr=s.iterator();
while(itr.hasNext()){
Map.Entry m=(Map.Entry)itr.next();
System.out.println(m.getKey()+"\t"+m.getValue()+"\t"+ m.hashCode());
}
When I execute this code, the value for key=Saral is Android. Is there any way that I can get the previous value for this key, which was J2EE?
No, you can't have that with a standard HashMap. The easiest solution would be to store a List as value in the map though, and then you can add multiple items to the list (Btw you should use generic collections too). To simplify, you could use a helper method like this:
void addToMap(Map<String, List<String>> map, String key, String value) {
List<String> list = map.get(key);
if (list == null) {
list = new ArrayList<String>();
map.put(key, list);
}
list.add(value);
}
Map<String, List<String>> map = new HashMap<String, List<String>>();
addToMap(map, "Amit", "Java");
addToMap(map, "Saral", "J2EE");
addToMap(map, "Saral", "Andriod");//same key but different value
addToMap(map, "Nitin", "PHP");
addToMap(map, "hj", "Spring1");
...
The helper method here is just an illustration - a full, robust implementation may need to include e.g. checks for duplicate values, depending on whether you allow them. If not, you may prefer using a Set instead of List.
Update
To print out the contents of this map, you need to use an embedded loop to iterate through the list of values for each map entry (btw you can use a foreach loop instead of an iterator):
for (Map.Entry<String, List<String>> m : map.entrySet())
{
for (String v : m.getValue())
{
System.out.println(m.getKey()+"\t"+v+"\t"+ m.hashCode());
}
}
A Map can contain at most one entry per key, so when you call map.put("Saral","Andriod"), the old "J2EE" value is removed. To support multiple values per key, you would need to maintain a Map<String, List<String>> or else a multi-map implementation such as Guava's Multimap.
As a side note I would recommend you start using generics, for example Map<String, String>, Iterator<String>, etc. for type safety at compile time.
The old value is overwritten (replaced). There will be only one mapping (entry) for one unique key. There fore it does not exist anymore so you can not retrieve it.
You cannot do this with standard implementations of Map that Java provides. However there are implementations of MultiMap (that's basically what you're after).
One example is this one from Google:
http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/Multimap.html
Note that you won't be able to just get this one interface, you'll need a few classes along with it.
As other have said, this won't work with a standard Map. However, Google's Guava provides a MultiMap interface, which you can use to store multiple values with a single key.
Example of use:
Multimap<String,String> multiMap = ArrayListMultimap.create();
multiMap.put("color", "red");
multiMap.put("color", "blue");
System.out.println(multiMap.get("color")); //returns a ["red', "blue"] list
LinkedHashMap description says "it maintains a doubly-linked list running through all of its entries" so I'm wondering how to get the last entry or key entered? Can I confidently downcast .values() to LinkedList to get that doubly-linked list and use .getLast() of that? Or is it an instance of some other Java collection?
I want to stick with java.util if possible.
Yes, you can get the last element. But you'll have to look at the suggestions from others to get the last element of the Collection<V> returned by values().
I checked in the source code that the returned values are indeed in the expected order:
The AbstactCollection<V> returned by LinkedListMap.values() is backed by an Iterator<V> over the values which is itself directly linked to the Iterator<K> over the keys. And obviously the Iterator<K> over the keys is implemented with the ordered doubly linked list.
No, sorry, you cannot.
The "maintained doubly-linked list" is not any java.util.LinkedList type or other collection. It's manually implemented in LinkedHashMap and LinkedHashMap.Entry classes.
You can only build LinkedList from values() and then use letLast() :
Foo last = new LinkedList<Foo>(myLinkedHashMap.values()).getLast();
Update: My previous answer was wrong. You cannot do it without modifying the default behaviour! See below why.
..how to get the last entry or key entered?
From the API description of LinkedHashMap you can read:
A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order. In insertion-ordered linked hash maps, merely changing the value associated with a key that is already contained in the map is not a structural modification. In access-ordered linked hash maps, merely querying the map with get is a structural modification.
So what does it all mean?
access-ordered - every time you do a put or a get the order of the elements changes
insertion-ordered - when inserting elements (for the first time) they are added last
For example:
map.put(1, 1);
map.put(2, 2);
map.put(1, 10);
System.out.println(map);
... will print {1=10, 2=2} with insertion-ordered and {2=2, 1=10} with *access-ordered'. The trouble is using access-ordered if of course if you do a get operations the order also changes.
How to fix
So... how to fix. Well the LinkedHashMap cannot be used directly used. So you can wrap it (do not care about the corny name) and override the put and the putAll methods so that they remove the key from the map first before putting it back in!
class BestLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
#Override
public V put(K key, V value) {
V last = super.remove(key);
super.put(key, value);
return last;
}
#Override
public void putAll(Map<? extends K, ? extends V> m) {
for (K key : m.keySet())
super.remove(key);
super.putAll(m);
}
}
Then to get the last element, either do:
wrap the output from in a LinkedList implementation:
V v = new LinkedList<V>(map.values()).getLast();
toArray() way:
Collection<V> values = map.values();
V v = values.toArray(new V[0])[values.size() - 1];
iterate to the last element using the iterator:
Iterator<V> it = values.iterator();
V last = null;
while (it.hasNext())
last = it.next();
I have "extended" the Jdk LinkedHashMap to allow that, you can take a look at: LinkedHashMapEx.java
I have a method that goes through the possible states in a board and stores them in a HashMap
void up(String str){
int a = str.indexOf("0");
if(a>2){
String s = str.substring(0,a-3)+"0"+str.substring(a-2,a)+str.charAt(a-3)+str.substring(a+1);
add(s,map.get(str)+1);
if(s.equals("123456780")) {
System.out.println("The solution is on the level "+map.get(s)+" of the tree");
//If I get here, I need to know the keys on the map
// How can I store them and Iterate through them using
// map.keySet()?
}
}
}
I'm interested in the group of keys. What should I do to print them all?
HashSet t = map.keySet() is being rejected by the compiler as well as
LinkedHashSet t = map.keySet()
Use:
Set<MyGenericType> keySet = map.keySet();
Always try to specify the Interface type for collections returned by these methods. This way regardless of the actual implementation class of the Set returned by these methods (in your case map.keySet()) you would be ok. This way if the next release the jdk guys use a different implementation for the returned Set your code will still work.
map.keySet() returns a View on the Keys of the map. Making changes to this view results in changing the underlying map though those changes are limited. See the javadoc for Map:
http://java.sun.com/j2se/1.5.0/docs/api/java/util/Map.html#keySet%28%29
Map<String, String> someStrings = new HashMap<String, String>();
for(Map.Entry<String, String> entry : someStrings.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
}
This is how I like to iterate through Maps. If you specifically want just the keySet(), that answer is elsewhere on this page.
for ( String key : map.keySet() ) {
System.out.println( key );
}
Set t = map.ketSet()
The API does not specify what type of Set is returned.
You should try to declare variables as the interface rather than a particular implementation.
Just
Set t = map.keySet();
Unless you're using an older JDK, I think its a little cleaner to use generics when using the Collections classes.
So thats
Set<MyType> s = map.keySet();
And then if you just iterate through them, then you can use any kind of loop you'd like. But if you're going to be modifying the map based on this keySet, you you have to use the keySet's iterator.
All that's guaranteed from keySet() is something that implements the interface Set. And that could possibly be some undocumented class like SecretHashSetKeys$foo, so just program to the interface Set.
I ran into this trying to get a view on a TreeSet, the return type ended up being TreeSet$3 on close examination.
Map<String, Object> map = new HashMap<>();
map.put("name","jaemin");
map.put("gender", "male");
map.put("age", 30);
Set<String> set = map.keySet();
System.out.println("this is map : " + map);
System.out.println("this is set : " + set);
It puts the key values in the map into the set.
From Javadocs HashMap has several methods that can be used to manipulate and extract data from a hasmap.
public Set<K> keySet()
Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation), the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support the add or addAll operations.
Specified by:
keySet in interface Map
Overrides:
keySet in class AbstractMap
Returns:
a set view of the keys contained in this map
so if you have a map myMap of any datatype , such that the map defined as map<T> , if you iterate it as follows:
for (T key : myMap.keySet() ) {
System.out.println(key); // which represent the value of datatype T
}
e.g if the map was defined as Map<Integer,Boolean>
Then for the above example we will have:
for (Integer key : myMap.keySet()){
System.out.println(key) // the key printed out will be of type Integer
}