Join two maps by key - java

I have two maps:
Map<Integer, String> mapOne = {(1,"a"), (2, "b")};
Map<Integer, Double> mapTwo = {(1,10.0), (2,20.0)};
and I want to combine this maps into one by Integer value, so the result map is
Map<String, Double> mapResult = {("a",10.0), ("b",20.0)};
Is there any way to do this easier than iterate over entry set?

Assuming that the keys of the two maps match and that the maps have the same number of entries, with Java 8 you can write it in one line with:
Map<String, Double> map = mapOne.entrySet().stream()
.collect(toMap(e -> e.getValue(),
e -> mapTwo.get(e.getKey())));
So you start from the first map and create a new map where the keys are the values of mapOne and the values are the corresponding values in mapTwo.
Technically this is somewhat equivalent to iterating over the entry set of the first map though.
Note: requires import static java.util.stream.Collectors.toMap;

Looks like only iteration:
#Test
public void testCollection() {
Map<Integer, String> mapOne = new HashMap<Integer, String>();
mapOne.put(1, "a");
mapOne.put(2, "b");
Map<Integer, Double> mapTwo = new HashMap<Integer, Double>();
mapTwo.put(1, 10.0);
mapTwo.put(2, 20.0);
Map<String, Double> mapResult = new HashMap<String, Double>();
Set<Integer> keySet = mapOne.keySet();
keySet.retainAll(mapTwo.keySet());
for (Integer value : keySet) {
mapResult.put(mapOne.get(value), mapTwo.get(value));
}
System.out.println(mapResult);
}

If the maps were the same type, you could use a putAll(), but since you are changing the key value pairs, it looks like you are going to have to iterate over each integer, get() from each map, then put(mapOneVal,mapTwoVal)
for(int i=0;i<max;i++){
String key = mapOne.get(i);
Double val = maptwo.get(i);
if(key!=null && val!=null)
map3.put(key,val);
}

Related

Best way to find element in List Java [duplicate]

It's a simple question,
I have a simple HashMap of which i want to reverse the keys and values.
HashMap<Character, String> myHashMap = new HashMap<Character, String>();
myHashMap.put('a', "test one");
myHashMap.put('b', "test two");
and I want to create a new HashMap in which i put the opposites.
HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();
e.g. Keys "test one" & "test two" and values 'a' & 'b'.
They all are unique, yes
If you're sure that your values are unique you can iterate over the entries of your old map .
Map<String, Character> myNewHashMap = new HashMap<>();
for(Map.Entry<Character, String> entry : myHashMap.entrySet()){
myNewHashMap.put(entry.getValue(), entry.getKey());
}
Alternatively, you can use a Bi-Directional map like Guava provides and use the inverse() method :
BiMap<Character, String> myBiMap = HashBiMap.create();
myBiMap.put('a', "test one");
myBiMap.put('b', "test two");
BiMap<String, Character> myBiMapInversed = myBiMap.inverse();
As java-8 is out, you can also do it this way :
Map<String, Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);
Map<Integer, String> mapInversed =
map.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey))
Finally, I added my contribution to the proton pack library, which contains utility methods for the Stream API. With that you could do it like this:
Map<Character, String> mapInversed = MapStream.of(map).inverseMapping().collect();
Apache commons collections library provides a utility method for inversing the map. You can use this if you are sure that the values of myHashMap are unique
org.apache.commons.collections.MapUtils.invertMap(java.util.Map map)
Sample code
HashMap<String, Character> reversedHashMap = MapUtils.invertMap(myHashMap)
If the values are not unique, the safe way to inverse the map is by using java 8's groupingBy function
Map<String, Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);
Map<Integer, List<String>> mapInversed =
map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())))
I wrote a simpler loop that works too (note that all my values are unique):
HashMap<Character, String> myHashMap = new HashMap<Character, String>();
HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();
for (char i : myHashMap.keySet()) {
reversedHashMap.put(myHashMap.get(i), i);
}
To answer your question on how you can do it, you could get the entrySet from your map and then just put into the new map by using getValue as key and getKey as value.
But remember that keys in a Map are unique, which means if you have one value with two different key in your original map, only the second key (in iteration order) will be kep as value in the new map.
Iterate through the list of keys and values, then add them.
HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();
for (String key : myHashMap.keySet()){
reversedHashMap.put(myHashMap.get(key), key);
}
private <A, B> Map<B, A> invertMap(Map<A, B> map) {
Map<B, A> reverseMap = new HashMap<>();
for (Map.Entry<A, B> entry : map.entrySet()) {
reverseMap.put(entry.getValue(), entry.getKey());
}
return reverseMap;
}
It's important to remember that put replaces the value when called with the same key. So if you map has two keys with the same value only one of them will exist in the inverted map.
Tested with below sample snippet, tried with MapUtils, and Java8 Stream feature. It worked with both cases.
public static void main(String[] args) {
Map<String, String> test = new HashMap<String, String>();
test.put("a", "1");
test.put("d", "1");
test.put("b", "2");
test.put("c", "3");
test.put("d", "4");
test.put("d", "41");
System.out.println(test);
Map<String, String> test1 = MapUtils.invertMap(test);
System.out.println(test1);
Map<String, String> mapInversed =
test.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
System.out.println(mapInversed);
}
Output:
{a=1, b=2, c=3, d=41}
{1=a, 2=b, 3=c, 41=d}
{1=a, 2=b, 3=c, 41=d}
Use forEach introduced in Java 8
Map<Short, String> regularMap = new HashMap<>();
Map<String, Short> inversedMap = new HashMap<>();
regularMap.forEach((key, value) -> inversedMap.put(value, key));
for reverting the map, in your case:
private void reverseMap(Map<Character, String> map) {
Map<String, Character> newList = new HashMap<>();
map.forEach((key, value) -> newList.put(value, key));
System.out.println(newList);
}
or you can traverse the old hashmap
HashMap<String, Character> newList = new HashMap<String, Character>();
for (String key : list.keySet()){
newList.put(list.get(key), key);
}
For Reversing the Array of Dictionary. (If values are Unique)
private void reverseArrayMap(List<Map<String, String>> list) {
// reversing the array of dictionary
List<Map<String, String>> newList = new ArrayList<>();
Map<String, String> resDic = new HashMap<>();
for (Map<String, String> map : list) {
map.forEach((key, value) -> resDic.put(value, key));
newList.add(resDic);
}
System.out.println("Original Array of Dictionary" + list);
System.out.println("Reversed Array of Dictionary" + newList);
}
Java :
Simple approach, No need for java 8
Map<String,String> map=new HashMap<>();
Map<String,String> mapInv=new HashMap<>();
for (String key : map.keySet())
mapInv.put(map.get(key), key);
Java 8:
forEach() is a new method to iterate the elements. It is defined in Iterable and Stream interface.
Map<String,String> map=new HashMap<>();
Map<String,String> mapInv=new HashMap<>();
map.forEach((key, value) -> mapInv.put(value, key));
Kotlin :
val map: Map<String, String> = HashMap()
val mapInv: MutableMap<String?, String> = HashMap()
for (key in map.keys) mapInv[map[key]] = key

I want to compare the each value in a java map with another value

If a value matches with another value then, i want to get the key,value pair corresponding to that value into a new map and values that doesn't match i.e unique key,value pairs into another map.
Eg:
Map<String,Double> map = new HashMap<String,Double>();
map.put("First",123.12345); //data1
map.put("Second",234.3456); //data2
map.put("Third",576.9876); //data3
map.put("Fourth",123.12345);//data4
map.put("Fifth",234.3456); //data5
map.put("Sixth",999.8888); //data6
map.put("Seventh",677.4578); //data7
Now here (data1 and data4) values (data2 and data5) and match and i want to store these (key,value) pairs in a new Map
Similarly data3, data and data7 have unique values and i want to store these (key,value) pairs in another new Map.
Any help is appreciated.
Thanks in advance.
You grouping by the map value and collect those entry with same value into a Map.
Map<Double, Map<String, Double>> result =
map.entrySet().stream()
.collect(groupingBy(Entry::getValue, toMap(Entry::getKey, Entry::getValue)));
This will give you result like:
{
123.12345 -> {
First -> 123.12345,
Fourth -> 123.12345
},
234.3456 -> ...
}
In java 7:
Map<Double, Map<String, Double>> result = new HashMap<>();
for (Entry<String, Double> mapping : map.entrySet()) {
Double value = mapping.getValue();
if (!result.containsKey(value)) {
result.put(value, new HashMap<>());
}
// Add new pair to map
result.get(value).put(mapping.getKey(), value);
}

Comparing two hash-maps and printing intersections

I have two hash maps: one contains an Integer key and String value.
The other contains an Integer key and float value.
Code
Map<Integer,String> mapA = new HashMap<>();
mapA.put(1, "AS");
mapA.put(2, "Wf");
Map<Integer,Float> mapB = new HashMap<>();
mapB.put(2, 5.0f);
mapB.put(3, 9.0f);
My question is how to compare the two hash maps using the integer key value? I want to print the bitmap value when the key values are the same.
You can just iterate on the keys of mapA and check if it is present in mapB then add the value to a third mapC for example.
Map<String, float> mapC = new HashMap<String, float>();
for (Integer key : mapA.keySet()) {
if (mapB.containsKey(key)) {
mapC.put(mapA.get(key), mapB.get(key));
}
}
Compare keys in two map by using mapB iterator.
Iterator<Entry<Integer, Float>> iterator = mapB.entrySet().iterator();
while(iterator.hasNext()) {
Entry<Integer, Float> entry = iterator.next();
Integer integer = entry.getKey();
if(mapA.containsKey(integer)) {
System.out.println("Float Value : " + entry.getValue());
}
}
If you are allowed to modify mapB, then the solution is as simple as mapB.keySet().retainAll(mapA.keySet());.
This will only leave those entries in mapB that have a corresponding key in mapA, because the set returned by keySet() is backed by the map itself, any changes made to it will be reflected to the map.
yes i got solution...
if(mapB.containsKey(position)){
Log.e("bucky",mapB.get(position));}
position means integer value.
With Java 8 Streams API:
Map<Integer, Object> matchInBothMaps = mapA
.entrySet()
.stream()
.filter(map -> mapB.containsKey(map.getKey()))
.collect(Collectors.toMap(map -> map.getKey(),
map -> map.getValue()));
System.out.println(matchInBothMaps);

What is the best practices to merge two maps

How can I add a new map to existing map. The maps have the same type Map<String, Integer>. If the key from new map exists in the old map the values should be added.
Map<String, Integer> oldMap = new TreeMap<>();
Map<String, Integer> newMap = new TreeMap<>();
//Data added
//Now what is the best way to iterate these maps to add the values from both?
By add, I assume you want to add the integer values, not create a Map<String, List<Integer>>.
Before java 7, you'll have to iterate as #laune showed (+1 to him). Otherwise with java 8, there is a merge method on Map. So you could do it like this:
Map<String, Integer> oldMap = new TreeMap<>();
Map<String, Integer> newMap = new TreeMap<>();
oldMap.put("1", 10);
oldMap.put("2", 5);
newMap.put("1", 7);
oldMap.forEach((k, v) -> newMap.merge(k, v, (a, b) -> a + b));
System.out.println(newMap); //{1=17, 2=5}
What it does is that for each key-value pair, it merges the key (if it's not yet in newMap, it simply creates a new key-value pair, otherwise it updates the previous value hold by the existing key by adding the two Integers)
Also maybe you should consider using a Map<String, Long> to avoid overflow when adding two integers.
for( Map.Entry<String,Integer> entry: newMap.entrySet() ) {
// get key and value from newMap and insert/add to oldMap
Integer oldVal = oldMap.get( entry.getKey() );
if( oldVal == null ){
oldVal = entry.getValue();
} else {
oldVal += entry.getValue();
}
newMap.put( entry.getKey(), oldVal );
}
Hope that this is what you meant

iterating two maps into a third map on key from both maps

I have two maps with key as an integer and value as a double.
I want to create a third map sorted on key and value would be a list of doubles from both the maps.
map1:
1, 90.00
5, 75.45
8, 76.50
map2:
4, 12.00
5, 322.09
8, 11.09
9, 21.00
final map:
1, (90.00,0.00)
5, (75.45,322.09)
8, (76.50,11.09)
9, (0.00, 21.00)
As clear from above, if a key in one of the map is missing in the other map, the value in the final map for the other map should be defaulted to 0.00
Map firstMap = new HashMap<Integer, Double>();
Map secondMap = new HashMap<Integer, Double>();
Map finalMap = new HashMap<Integer, List<Double>>();
firstMap.put(1, 90.00);
firstMap.put(5, 75.45);
firstMap.put(8, 76.50);
secondMap.put(4, 12.00);
secondMap.put(5, 322.09);
secondMap.put(8, 11.09);
secondMap.put(9, 21.00);
I can use putAll method to put all keys into the third map. But how to put the values as I want ?
Thanks for reading!
Simply do
// Create a sorted map
Map<Integer, List<Double>> finalMap = new TreeMap<Integer, List<Double>>();
Set<Integer> keys = new HashSet<Integer>();
keys.addAll(firstMap.keySet());
keys.addAll(secondMap.keySet());
for (Integer key : keys) {
double first = firstMap.containsKey(key) ? firstMap.get(key) : 0.0;
double second = secondMap.containsKey(key) ? secondMap.get(key) : 0.0;
finalMap.put(key, Arrays.asList(first, second));
}
Using Guava it's as simple as
Multimap<Integer, Double> finalMultiMap = ArrayListMultimap.create();
finalMultiMap.putAll(Multimaps.forMap(firstMap));
finalMultiMap.putAll(Multimaps.forMap(secondMap));
Map<Integer, Collection<Double>> finalMap = finalMultiMap.asMap();
The following code would perform the requested operation
List<Map<Integer, Double>> originals = getOriginalLists();
Map<Integer, List<Double>> result = new HashMap<Integer, List<Double>>();
for (Map<Integer, Double> original : originals) {
for (Map.Entry<Integer, Double> entry : original.entrySet()) {
if (!result.containsKey(entry.getKey())) {
result.put(entry.getKey(), new ArrayList<Double>());
}
result.get(entry.getKey()).add(entry.getValue());
}
}
It works one a list of maps, so the solutions is not restricted to two maps.

Categories