adding the values of two maps when same key - java

Looking for a standard library function way in Java for adding the values in two maps based on their keys.
Map A: {a=1, b=2}
Map B: {a=2, c=3}
Resulting map:
Map C: {a=3, b=2, c=3}
I know this can be coded in a few lines. I also know functional programming is great for this. I am just wandering if there is a standard function or syntax people use out there.
Something like (but probably more generic than):
public HashMap<String,Double> addValues(HashMap<String,Double> a, HashMap<String,Double> b) {
HashMap<String,Double> ret = new HashMap<String,Double>(a);
for (String s : b.keySet()) {
if (ret.containsKey(s)) {
ret.put(s, b.get(s) + ret.get(s));
} else {
ret.put(s, b.get(s));
}
}
return ret;
}

An alternative which does essentially the same thing, using Java 8 new getOrDefault method:
Set<String> keys = new HashSet<> (a.keySet());
keys.addAll(b.keySet());
Map<String, Integer> c = new HashMap<>();
for (String k : keys) {
c.put(k, a.getOrDefault(k, 0) + b.getOrDefault(k, 0));
}
But if using Java 8, you may as well stream the keys and make it a one liner:
Map<String, Object> c = Stream.concat(a.keySet().stream(), b.keySet().stream())
.distinct()
.collect(toMap(k -> k, k -> a.getOrDefault(k, 0) + b.getOrDefault(k, 0)));

I think what you are doing is just fine. I can think of one other way though, using a MultiMap. You can add all your elements to a multimap and then run a summation function over all the values for each key at the end.

Here's a version that allows for any number of Maps to be combined:
public static Map<String, Integer> addKeys(Map<String, Integer>... maps) {
Set<String> keys = new HashSet<String>();
for (Map<String, Integer> map : maps)
keys.addAll(map.keySet());
Map<String, Integer> result = new HashMap<String, Integer>();
for (String key : keys) {
Integer value = 0;
for (Map<String, Integer> map : maps)
if (map.containsKey(key))
value += map.get(key);
result.put(key, value);
}
return result;
}
Usage:
public static void main(String[] args){
Map<String, Integer> a = new HashMap<String, Integer>();
a.put("a", 1);
a.put("b", 2);
Map<String, Integer> b = new HashMap<String, Integer>();
b.put("a", 2);
b.put("c", 3);
Map<String, Integer> c = addKeys(a, b);
System.out.println(c);
}
Ouptut:
{b=2, c=3, a=3}
Unfortunately, it's not possible as far as I can see to create a generic method:
public static <K, V extends Number> Map<K, V> addKeys(Class<V> cls, Map<K, V>... maps);
Because the Number class doesn't support the + operator. Which seems a bit daft to me...

Related

How to insert the same value for multiple keys of an HashMap using Java Streams

Say I have a HashMap and I want to insert the same value to a list of keys. How can I do this with Java 8 without iterating through all the keys and inserting the value? This is more of a Java Streams question.
Here is the straight forward way of doing it. This is a sample code that I wrote to demonstrate what I wanted to achieve.
public void foo(List<String> keys, Integer value) {
Map<String, Integer> myMap = new HashMap<>();
for (String key : keys) {
myMap.put(key, value);
}
}
Is there a simpler way of doing the above using Java 8 streams? How can I avoid the for loop using Java 8 streams. Thanks!
[Edit-1] A better code snippet below.
public void foo() {
Map<String, Integer> myMap = new HashMap<>();
List<String> keys = getKeysFromAnotherFunction();
Integer value = getValueToBeInserted(); // Difficult to show my actual use case. Imagine that some value is getting computed which has to be inserted for the keys.
for (String key : keys) {
myMap.put(key, value);
}
List<String> keys2 = getNextSetOfKeys();
Integer newValue = getValueToBeInserted();
for (String key : keys2) {
myMap.put(key, newValue);
}
}
Using collector, something like:
Map<String, Integer> myMap = keys.stream()
.collect(Collectors.toMap(key -> key,
val -> value, (a, b) -> b));
I think that your question is about factoring out some piece of code more than converting traditional for loops into stream constructs.
Suppose you have the following generic utility method:
public static <K, V, M extends Map<K, V>> M fillMap(
Supplier<List<K>> keysFactory,
Supplier<V> singleValueFactory,
Supplier<M> mapFactory) {
M map = mapFactory.get();
List<K> keys = keysFactory.get();
V singleValue = singleValueFactory.get();
keys.forEach(k -> map.put(k, singleValue));
return map;
}
Then, you could use the above method as follows:
Map<String, Integer> myMap = fillMap(() -> getKeysFromAnotherFunction(),
() -> getValueToBeInserted(),
HashMap::new); // create HashMap
myMap = fillMap(() -> getNextSetOfKeys(),
() -> getValueToBeInserted(),
() -> myMap); // use previously created map
There are variants for the code above, i.e., the method could receive a Map<K, V> instance instead of a Supplier<Map<K, V>>, or it might even be overloaded to support both variants.

Finding the Key from Value in Map

So I am having a bit of trouble understanding how to do this. I am building a word counter in Java using Map<String, Integer> where a word is the String and the amount of times that word was said in a .txt document is Integer. This is all working great...but I am trying to develop a part where it will display at the bottom what the top 5 results are ---> what the top 5 map.values() are.
The problem I have run into is after I find the value, I can't get the String with it.
Any suggestions would be very helpful to me.
You need to use the Map.Entry<String, Integer> to get the pair of the key and value.
The values() method returns only values, whereas the keySet() method returns only the keys.
Firstly, you should sort your map, based on values, to get the top five results.
The straightforward approach uses a Comparator. See the answer here for more.
Then you simply get the first five entries of the map.getEntrySet(). It would be easier to use an Iterator for this.
UPDATE:
Set<Entry<String, Integer>> set = wordCount.entrySet();
List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(set);
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
int topResults = 5;
Iterator<Entry<String, Integer>> iter = list.iterator(); //refer the sorted collection
while (iter.hasNext() && topResults > 0 ) {
Map.Entry<String, Integer> entry = iter.next();
System.out.println(entry.getKey() + "->" + entry.getValue());
topResults --;
}
a) Iterate over the map, this way you have both keys and values accessible:
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
// ...
}
b) build a second map for reverse lookup, e.g. Map - note that this is likely not a good idea here as you may have duplicate keys (same number for different words)
c) consider using a bidimap - this is a map which you can query both by key and by value.
I suggest you to override Comparator and build your Map constructor based on it.
Code is showed below:
class ValueComparator implements Comparator {
Map map;
public ValueComparator(Map map) {
this.map = map;
}
public int compare(Object keyA, Object keyB) {
Comparable valueA = (Comparable) map.get(keyA);
Comparable valueB = (Comparable) map.get(keyB);
return valueB.compareTo(valueA);
}
}
public class YourClass{
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 10);
map.put("b", 30);
map.put("c", 50);
map.put("d", 40);
map.put("e", 20);
System.out.println(map);
Map sortedMap = sortByValue(map);
System.out.println(sortedMap);
}
public static Map sortByValue(Map unsortedMap) {
Map sortedMap = new TreeMap(new ValueComparator(unsortedMap));
sortedMap.putAll(unsortedMap);
return sortedMap;
}
}

How to receive difference of maps in java?

I have two maps:
Map<String, Object> map1;
Map<String, Object> map2;
I need to receive difference between these maps. Does exist may be apache utils how to receive this difference?
For now seems need take entry set of each map and found diff1 = set1 - set2 and diff2 = set2- set1.
After create summary map =diff1 + diff2
It looks very awkwardly. Does exist another way?
Thanks.
How about google guava?:
Maps.difference(map1,map2)
Here is a simple snippet you can use instead of massive Guava library:
public static <K, V> Map<K, V> mapDifference(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) {
Map<K, V> difference = new HashMap<>();
difference.putAll(left);
difference.putAll(right);
difference.entrySet().removeAll(right.entrySet());
return difference;
}
Check out the whole working example
If I understood well you are trying to calculate symmetric difference beetween the two maps entry sets.
Map<String, Object> map1;
Map<String, Object> map2;
Set<Entry<String, Object>> diff12 = new HashSet<Entry<String, Object>>(map1.entrySet());
Set<Entry<String, Object>> diff21 = new HashSet<Entry<String, Object>>(map2.entrySet());
Set<Entry<String, Object>> result;
diff12.removeAll(map2.entrySet());
diff21.removeAll(map1.entrySet());
diff12.addAll(diff21);
Considering the awkward behavior you mentioned, let's take a closer look at the above code behavior. For example if we take the numerical example from the above given link:
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("a", 1);
map1.put("b", 2);
map1.put("c", 3);
map1.put("d", 4);
Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("a", 1);
map2.put("d", 4);
map2.put("e", 5);
After you calculate the difference as shown, the output:
System.out.println(Arrays.deepToString(diff12.toArray()));
gives:
[e=5, c=3, b=2]
which is the correct result. But, if we do it like this:
public class CustomInteger {
public int val;
public CustomInteger(int val) {
this.val = val;
}
#Override
public String toString() {
return String.valueOf(val);
}
}
map1.put("a", new CustomInteger(1));
map1.put("b", new CustomInteger(2));
map1.put("c", new CustomInteger(3));
map1.put("d", new CustomInteger(4));
map2.put("a", new CustomInteger(1));
map2.put("d", new CustomInteger(4));
map2.put("e", new CustomInteger(5));
the same algorithm gives the following output:
[e=5, a=1, d=4, d=4, b=2, a=1, c=3]
which is not correct (and might be described as awkward :) )
In the first example the map is filled with int values wich are automatically boxed to Integer values.
The class Integer has its own implementation of equals and hashCode methods.
The class CustomInteger does not implement these methods so it inherits them from the omnipresent Object class.
The API doc for the removeAll method from the Set interface says the following:
Removes from this set all of its elements that are contained in the specified collection
(optional operation). If the specified collection is also a set, this operation effectively modifies this set so that its value is the asymmetric set difference of the two sets.
In order to determine which elements are contained in both collections, the removeAll method uses the equals method of the collection element.
And that's the catch: Integer's equals method returns true if the two numeric values are the same, while Object's equals method will return true only if it is the same object, e.g.
:
Integer a = 1; //autoboxing
Integer b = new Integer(1);
Integer c = 2;
a.equals(b); // true
a.equals(c); // false
CustomInteger d = new CustomInteger(1);
CustomInteger e = new CustomInteger(1);
CustomInteger f = new CustomInteger(2);
d.equals(e); //false
d.equals(f) // false
d.val == e.val //true
d.val == f.val //false
If it's still a bit fuzzy I strongly suggest reading the following tutorials:
Learning the Java language
Collections
Set<Entry<String, Object>> diff = new HashSet<Entry<String, Object>>((map1.entrySet()));
diff.addAll(map2.entrySet());//Union
Set<Entry<String, Object>> tmp = new HashSet<Entry<String, Object>>((map1.entrySet()));
tmp.retainAll(map2.entrySet());//Intersection
diff.removeAll(tmp);//Diff
Building on Vlad's example to work with maps of different sizes
public static <K, V> Map<K, V> mapDiff(Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) {
Map<K, V> difference = new HashMap<>();
difference.putAll(left);
difference.putAll(right);
difference.entrySet().removeAll(left.size() <= right.size() ? left.entrySet() : right.entrySet());
return difference;
}
Try using guava's MapDifference.
Simple way to do it. if you want complex way, you can change filter to compare value.
Map<String, Object> map1 = new HashMap<String, Object>() {{
put("A", "1");
put("B", "2");
put("C", "3");
}};
Map<String, Object> map2 = new HashMap<String, Object>() {{
put("A", "1");
put("B", "2");
put("D", "3");
}};
Map<String, Object> newList = map1.keySet().stream().filter(str -> !map2.containsKey(str)).collect(Collectors.toMap(v -> v, v -> map1.get(v)));
Map<String, Object> oldList = map2.keySet().stream().filter(str -> !map1.containsKey(str)).collect(Collectors.toMap(v -> v, v -> map2.get(v)));
System.out.println(newList);
System.out.println(oldList);

Merging two Maps

I have two maps whose keys are Strings and whose values are Set<MyObject>. Given two Maps, what is the easiest way to merge them such that if two keys are identical, the value is a union of the two sets. You can assume values are never null and if it is useful, we can make these Maps SortedMaps.
You can do this with a stream fairly easily:
Map<T, Set<U>> merged = Stream.of(first, second)
.map(Map::entrySet)
.flatMap(Set::stream)
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> {
HashSet<U> both = new HashSet<>(a);
both.addAll(b);
return both;
}));
This splits the maps into their Entrys and then joins them with a Collector which resolves duplicates by adding both values to a new HashSet.
This also works for any number of maps.
Some variations which produce the same result:
Stream.of(first, second).flatMap(m -> m.entrySet().stream())
.collect(...);
Stream.concat(first.entrySet().stream(), second.entrySet().stream())
.collect(...); //from comment by Aleksandr Dubinsky
The third parameter for Collectors.toMap is not necessary if there are no duplicate keys.
There is another Collectors.toMap with a fourth parameter that lets you decide the type of the Map collected into.
Are we talking about HashMap instances. In that case lookup is O(1), so you can just take one map, iterate over the entries of that map, see whether the other map contains that key. If not, just add the set. If it contains the key, take the union of the two sets (by adding all elements of one set to another)
To illustrate with some code, where I used a Set to have autocompletion in my IDE
Map<String, Set<Double>> firstMap = new HashMap<String, Set<Double>>( );
Map<String, Set<Double>> secondMap = new HashMap<String, Set<Double>>( );
Set<Map.Entry<String, Set<Double>>> entries = firstMap.entrySet();
for ( Map.Entry<String, Set<Double>> entry : entries ) {
Set<Double> secondMapValue = secondMap.get( entry.getKey() );
if ( secondMapValue == null ) {
secondMap.put( entry.getKey(), entry.getValue() );
}
else {
secondMapValue.addAll( entry.getValue() );
}
}
static void mergeSet(Map<String, Set<String>> map1, Map<String, Set<String>> map2) {
map1.forEach((key1, value1) -> {
map2.merge(key1, value1, (key2, value2) -> key2).addAll(value1);
});
}
How about this (untested):
Map<String,Set<Whatever>> m1 = // input map
Map<String,Set<Whatever>> m2 = // input map
Map<String,Set<Whatever>> ret = // new empty map
ret.putAll(m1);
for(String key : m2.keySet()) {
if(ret.containsKey(key)) {
ret.get(key).addAll(m2.get(key));
} else {
ret.put(key,m2.get(key));
}
}
This solution doesn't modify the input maps, and because it is short and relies on API methods only, I find it quite readable.
Note that putAll() and addAll() are both optional methods in Map and Set. Consequently (and in order to get O(1) lookup), I'd recommend using HashMap and HashSet.
Note that because neither HashSet or HashMap are synchronised you will need to look for some other solution if you want thread-safe code.
The following should merge a map1 into map2 (untested):
for (Entry<String, Set<???>> entry : map1.entrySet( ))
{
Set<???> otherSet = map2.get(entry.getKey( ));
if (otherSet == null)
map2.put(entry.getKey( ), entry.getValue ( ));
else
otherSet.addAll(entry.getValue( ));
}
I don't know what you've parameterized your Sets on, hence the <???>: replace as appropriate.
Something like this (untested):
// Assume all maps are of the same generic type.
public static Map<String, Set<MyObject>> mergeAll(Map m1, Map m2) {
Map<String, Set<MyObject>> merged = new HashMap();
// Merge commom entries into the new map.
for (Map.Entry<String, Set<MyObject>> entry : m1.entrySet()) {
String key = entry.getKey();
Set<MyObject> s1 = new HashSet(entry.getValue());
Set<MyObject> s2 = m2.get(key);
if (s2 != null) s1.addAll(s2);
merged.put(key, s1);
}
// Add entries unique to m2 to the new map.
for (String key : m2.keys()) {
if (!s1.containsKey(key)) merged.put(key, new HashSet(m2.get(key)));
}
return merged;
}
Note that this solution does not mutate either of its arguments.
Map<Integer,String> m1=new HashMap<Integer,String>();
Map<Integer,String> m2=new HashMap<Integer,String>();
m1.put(1,"one");
m1.put(2,"two");
m2.put(3,"three");
m2.put(2,"two");
Set<Integer> s=m2.keySet();
for(int i:s){
if(m1.get(i)==null){
m1.put(i,m2.get(i));
}
}
System.out.println(m1);
Note that all other answers will eventually augment the original sets which you might not want for all use cases, if you don't want that just use a third map as output and create a new set for each key
public static void merge2Maps(Map<String, Set<Double>> a, Map<String, Set<Double>> b, Map<String, Set<Double>> c){
for (Map.Entry<String, Set<Double>> entry : a.entrySet()) {
Set<Double> set = new HashSet<Double>();
c.put(entry.getKey(), set);
set.addAll(entry.getValue());
}
for (Map.Entry<String, Set<Double>> entry : b.entrySet()) {
String key = entry.getKey();
Set<Double> set = c.get(key);
if (set == null) {
set = new HashSet<Double>();
c.put(entry.getKey(), set);
}
set.addAll(entry.getValue());
}
}
If you want to end up with immutable data structures to prevent manipulation of your merged map and map's Set instances then you can take this approach. This solution uses Google's Guava library.
public <K,T> Map<K, Set<T>> mergeToImmutable (
final Map<K, Set<T>> left,
final Map<K, Set<T>> right)
{
return Maps.toMap(
Sets.union(
checkNotNull(left).keySet(),
checkNotNull(right).keySet()
),
new Function<K, Set<T>> () {
#Override
public Set<T> apply (K input) {
return ImmutableSet.<T>builder()
.addAll(MoreObjects.firstNonNull(left.get(input), Collections.<T>emptySet()))
.addAll(MoreObjects.firstNonNull(right.get(input), Collections.<T>emptySet()))
.build();
}
}
);
}
If you define a method to unite non-null Sets as:
static <T> Set<T> union(Set<T>... sets) {
return Stream.of(sets)
.filter(s -> s != null)
.flatMap(Set::stream)
.collect(Collectors.toSet());
}
then merging two maps m1 and m2 having Set<V> values can be performed as follows:
Map<String, V> merged
= union(m1.keySet(), m2.keySet())
.stream()
.collect(Collectors.toMap(k -> k, k -> union(m1.get(k), m2.get(k))));
Or even simpler:
Map<String, V> merged = new HashMap<>();
for (String k : union(m1.keySet(), m2.keySet())
merged.put(k, union(m1.get(k), m2.get(k)));
<K, V> Map<K, List<V>> mergeMapOfLists(Stream<Map<K, List<V>>> stream) {
return stream
.map(Map::entrySet) // convert each map to set of map's entries
.flatMap(Collection::stream) // convert each map entry to stream and flat them to one stream
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue,
(list1, list2) -> {
list1.addAll(list2);
return list1;
})); // convert stream to map; if key is duplicated execute merge fuction (append exisitng list with elements from new list)
}

Java invert map

I need create inverse map - select unique values and for them find keys.
Seems that only way is to iterate all key/value pairs, because entrySet returns set of <key,value> so value not unique?
The values in a map may not be unique. But if they are (in your case) you can do as you wrote in your question and create a generic method to convert it:
private static <V, K> Map<V, K> invert(Map<K, V> map) {
Map<V, K> inv = new HashMap<V, K>();
for (Entry<K, V> entry : map.entrySet())
inv.put(entry.getValue(), entry.getKey());
return inv;
}
Java 8:
public static <V, K> Map<V, K> invert(Map<K, V> map) {
return map.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getValue, Entry::getKey));
}
Example of usage:
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Hello", 0);
map.put("World!", 1);
Map<Integer, String> inv = invert(map);
System.out.println(inv); // outputs something like "{0=Hello, 1=World!}"
}
Side note: the put(.., ..) method will return the the "old" value for a key. If it is not null you may throw a new IllegalArgumentException("Map values must be unique") or something like that.
Take a look at Google Guava BiMap.
Example usage
Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
Map<String, Integer> inverted = HashBiMap.create(map).inverse();
To get an inverted form of a given map in java 8:
public static <K, V> Map<V, K> inverseMap(Map<K, V> sourceMap) {
return sourceMap.entrySet().stream().collect(
Collectors.toMap(Entry::getValue, Entry::getKey,
(a, b) -> a) //if sourceMap has duplicate values, keep only first
);
}
Example usage
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "one");
map.put(2, "two");
Map<String, Integer> inverted = inverseMap(map);
Seems that only way is to iterate all key/value pairs, because entrySet returns set of so value not unique?
It's one way at least. Here's an example:
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "one");
map.put(2, "two");
Map<String, Integer> inverted = new HashMap<String, Integer>();
for (Integer i : map.keySet())
inverted.put(map.get(i), i);
In case of non-unique values, this algorithm will map the last value found to it's key. (Since the iteration order is undefined for most maps, this should be as good as any solution.)
If you really do want to keep the first value found for each key, you could change it to
if (!inverted.containsKey(map.get(i)))
inverted.put(map.get(i), i);
I would give another approach to this problem giving an extra dimension:
duplicate values in EntrySet.
public static void main(String[] args) {
HashMap<Integer, String> s = new HashMap<Integer, String>();
s.put(1, "Value1");
s.put(2, "Value2");
s.put(3, "Value2");
s.put(4, "Value1");
/*
* swap goes here
*/
HashMap<String,List<Integer>> newMap = new HashMap<String, List<Integer>>();
for (Map.Entry<Integer, String> en : s.entrySet()) {
System.out.println(en.getKey() + " " + en.getValue());
if(newMap.containsKey(en.getValue())){
newMap.get(en.getValue()).add(en.getKey());
} else {
List<Integer> tmpList = new ArrayList<Integer>();
tmpList.add(en.getKey());
newMap.put(en.getValue(), tmpList);
}
}
for(Map.Entry<String, List<Integer>> entry: newMap.entrySet()){
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
T result will be that:
1 Value1 2 Value2 3 Value2 4 Value1 Value1 [1, 4] Value2 [2, 3]
Apache Commons Collections also provides a BidiMap interface for bi-directional maps, along with several implementations.
BidiMap JavaDoc
If your values duplicate and you need to store keys in list you can go with
val invertedMap = originalMap.entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry::getValue,
Collectors.mapping(Map.Entry::getKey, Collectors.toList()))
);
You have to assume that values may be identical, since the Map contract allows it.
In my opinion the best solution lies in using a wrapper. It will contain the original value, and add an id. Its hashCode() function will rely on the id, and you provide a Getter for the original value.
Code would be something like this:
public class MapKey
{
/**
* A new ID to differentiate equal values
*/
private int _id;
/**
* The original value now used as key
*/
private String _originalValue;
public MapKey(String originalValue)
{
_originalValue = originalValue;
//assuming some method for generating ids...
_id = getNextId();
}
public String getOriginalValue()
{
return _originalValue;
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + _id;
return result;
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MapKey other = (MapKey) obj;
if (_id != other._id)
return false;
return true;
}
#Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("MapKey value is ");
sb.append(_originalValue);
sb.append(" with ID number ");
sb.append(_id);
return sb.toString();
}
Inverting the map would be something like this:
public Map <MapKey, Integer> invertMap(Map <Integer, String> map)
{
Map <MapKey, Integer> invertedMap = new HashMap <MapKey, Integer>();
Iterator<Entry<Integer, String>> it = map.entrySet().iterator();
while(it.hasNext())
{
//getting the old values (to be reversed)
Entry<Integer, String> entry = it.next();
Integer oldKey = entry.getKey();
String oldValue = entry.getValue();
//creating the new MapKey
MapKey newMapKey = new MapKey(oldValue);
invertedMap.put(newMapKey, oldKey);
}
return invertedMap;
}
Printing the values something like this:
for(MapKey key : invertedMap.keySet())
{
System.out.println(key.toString() + " has a new value of " + invertedMap.get(key));
}
None of this code is tested, but I believe it's the best solution since it makes use of OO inheritance design instead of "c" style checks and allows you to display all the original keys and values.
With Guava
Multimaps.transformValues(Multimaps.index(map.entrySet(), Map.Entry::getValue),
Map.Entry::getKey)
You'll get a multimap (basically a map of lists) in return.

Categories