Iterating over a HashMap with a Pair(x,y) as the key - java

I have a HashMap:
resources = new HashMap<Pair, Resource>();
That I have instantiated...
resources.put(new Pair(x,y), new Resource());
Pair is a custom Pair class that I have created that has overridden .equals and .hashMap to avoid duplicate keys.
I want to iterate over resources so I can identify the unique instances I have created. More specifically, I need to identify the unique (x,y) pairs.
I have found solutions for iterating over HashMaps, but I'm a little confused on how to adapt this (shown below) to work with a key that is a Pair.
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
Thanks!

First of all, I think you mean you have overridden equals() and hashCode() methods in Pair class right?
How do you define unique Pair? I hope your definition of uniqueness is not based on equals() because if it is the case then all the key of HashMap is unique

It's no different. Map and Map.Entry are generic, so you specify parametrized types when you construct the map.
Map<Pair, String> keyToValue = new HashMap<>();
// put stuff in it
for (Map.Entry<Pair, String> entry: keyToValue.entrySet()) {
Pair pair = entry.getKey();
String value = entry.getValue();
// do stuff
}
In fact, your Pair class should probably be generified itself -- Pair<T,U>.
As for getting the unique pairs, you could just do Set<Pair> uniquePairs = keyToValue.keySet() or, if you didn't need the corresponding values at all, you could just use a HashSet -- Set<Pair> uniquePairs = new HashSet<>(). They will be as unique as your implementations of Pair.hash and Pair.equals define them to be.

Related

Store the values without overwriting

I have a Map<String, Integer> e.g.
"aaa", 1
"bbb", 2
"ccc", 3
"aaa", 4
The problem is that the HashMap does not store all key and values, as I've understood, when i try add the last pair ("aaa", 4), it will not be added, instead of this, the value for "aaa" (I mean 1) will be overwritten on 4.
I know, that I could create class, where I could store these pairs, but I need another solution. (without creating a new class)
EDIT ------------------------------------
Actually I have much more pairs, and I do not have uniques String or Integers, I mean that, if even I have two similar pairs they will be stored
A map, by definition, will have distinct keys. If you add a key-value pair and the key already exists, the new key-value pair will overwrite the existing key-value pair.
For your scenario, when you have multiple values against a single key, you can explore the following options
Option 1 : Since your key-value pairs are not unique, it can be stored as list of pairs. For every key-value pair, you can create a pair and insert it into the list.
List<Pair<String, Integer>> data = new ArrayList();
Pair<String, Integer> item = new Pair("abc", 1);
data.add(item);
This option does not give you optimized lookup capabilities that comes with Map.
Option 2. Create a Map<String, List<Integer>>. You'll not be able to do simple put operations on the map anymore, but you will be able to store all the items corresponding to each key without loss of information as well as retrieve them faster.
Create a List:
if (!map.containsKey("aaaa")) {
map.put("aaaa", new ArrayList<Integer>());
}
List<Integer> aaaaValues = map.get("aaaa");
aaaaValues.add(1);
aaaaValues.add(4);
...
If your values are unieque, use them as keys.
You don't have to create class. You can use List<org.apache.commons.lang3.tuple.Pair<String, Integer>>
Also one way, override equals and hashCode where you speak that object is unique only if String and Integer parameter is unique in pair
Map<String, Integer> map = new HashMap<String, Integer>(){
#Override
public boolean equals(Object o)
{
// your realization
}
#Override
public int hashCode()
{
// your realization
}
};

How can each element in Set be a Map.Entry object?

I am a bit confused. i was reading the map interface. It has to use entrySet() method for collection view to use iterator. entrySet() return a Set that contains the elements of map. Again, each of this Set element is a Map.Entry object. how is that possible? as Set contains only one field, whereas Map.Entry is a key value pair?
A map is basically a set of key => value mappings. In addition, the keys are unique and the values don't have to be. A key-value pair is encapsulated within a Map.Entry object. When you iterate over the entries of a map (= the set of key-value pairs), for each entry you can get the key with entry.getKey() and the value with entry.getValue().
In addition to the set of entries, a map also provides the set of keys, and the collection of values. For example, in a Map<String, Date>, you have the set of key-value pairs as Set<Map.Entry<String, Date>>, the set of keys as Set<String> and the collection of values as Collection<Date>.
A concrete example of iterating over entries:
Map<String, Date> map = new HashMap<String, Date>();
map.put("now", new Date());
map.put("now+", new Date());
for (Map.Entry<String, Date> entry : map.entrySet()) {
String key = entry.getKey();
Date value = entry.getValue();
System.out.println(String.format("%s => %s", key, value));
}
Another way to iterate is by keys:
for (String key : map.keySet()) {
Date value = map.get(key);
System.out.println(String.format("%s => %s", key, value));
}
But this is less efficient because for each key you have to perform a lookup to get the value, in contrast with using entries with direct access to values.
Set elements are objects, Map.Entry instance is also an object. All correct.
Consider the following: You can create your own Cat class with whichever properties you like. E.g.:
public class Cat {
private String name;
private String type;
private boolean isGrumpy;
// etc...
}
As long as you implement equals(Object) and hashCode(), instances of this class can be put in a Set, right?
So why should Map.Entry be different? Just think of it as a class with two members - key and value.

Getting the key and its specific value from map

I am using Map as follows
Map<String, String> propMap = new LinkedHashMap<String, String>();
and I saw that there is two methods that I can use keySet() (to get the list of keys)
and values to get the list of values but my question is how to relate between them
for example for key1 the value is 2.
I thought to use get value like follows
Map<String, String> propMap2 = propterm.getPropMap();
Set<String> keySet = propMap2.keySet();
But how I relate it to his respective value ?
You can use propMap.entrySet() method which returns a Map.Entry of key, value, if you want to use every pair of key and value: -
for (Map.Entry<String, String> entry: propMap.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
Or, if you want to know how to do this with propMap.keySet(), you can iterate over the Set<Key> you obtain, and for each key, use propMap.get(key), to get the value of a particular key: -
Set<String> keySet = propMap2.keySet();
for (String key: keySet) {
System.out.println(propMap.get(key));
}
From an answer from this post: -
With the later approach, if you are regularly accessing the key-value pair, then for each key, the map.get() method is called, which - in the case of a HashMap - requires that the hashCode() and equals() methods of the key object be evaluated in order to find the associated value*. In the first case (entrySet), that extra work is eliminated.

Retrieving the previous key-map value before it was overwritten in a HashMap

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

Using the keySet() method in HashMap

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
}

Categories

Resources