How to putAll on Java hashMap contents of one to another, but not replace existing keys and values?
Solution 1
It looks like you are willing to create a temporary Map
, so I'd do it like this:
Map tmp = new HashMap(patch);
tmp.keySet().removeAll(target.keySet());
target.putAll(tmp);
Here, patch
is the map that you are adding to the target
map.
Thanks to Louis Wasserman, here's a version that takes advantage of the new methods in Java 8:
patch.forEach(target::putIfAbsent);
Solution 2
Using Guava's Maps class' utility methods to compute the difference of 2 maps you can do it in a single line, with a method signature which makes it more clear what you are trying to accomplish:
public static void main(final String[] args) {
// Create some maps
final Map<Integer, String> map1 = new HashMap<Integer, String>();
map1.put(1, "Hello");
map1.put(2, "There");
final Map<Integer, String> map2 = new HashMap<Integer, String>();
map2.put(2, "There");
map2.put(3, "is");
map2.put(4, "a");
map2.put(5, "bird");
// Add everything in map1 not in map2 to map2
map2.putAll(Maps.difference(map1, map2).entriesOnlyOnLeft());
}
Solution 3
Just iterate and add:
for(Map.Entry e : a.entrySet())
if(!b.containsKey(e.getKey())
b.put(e.getKey(), e.getValue());
Edit to add:
If you can make changes to a, you can also do:
a.putAll(b)
and a will have exactly what you need. (all the entries in b
and all the entries in a
that aren't in b
)
Solution 4
You can make it in just 1 line if you change maps order in @erickson's solution:
mapWithNotSoImportantValues.putAll( mapWithImportantValues );
In this case you replace values in mapWithNotSoImportantValues with value from mapWithImportantValues with the same keys.
Solution 5
Java 8 solution using Map#merge
As of java-8 you can use Map#merge(K key, V value, BiFunction remappingFunction)
which merges a value into the Map
using remappingFunction
in case the key is already found in the Map
you want to put the pair into.
// using lambda
newMap.forEach((key, value) -> map.merge(key, value, (oldValue, newValue) -> oldValue));
// using for-loop
for (Map.Entry<Integer, String> entry: newMap.entrySet()) {
map.merge(entry.getKey(), entry.getValue(), (oldValue, newValue) -> oldValue);
}
The code iterates the newMap
entries (key
and value
) and each one is merged into map
through the method merge
. The remappingFunction
is triggered in case of duplicated key and in that case it says that the former (original) oldValue
value will be used and not rewritten.
With this solution, you don't need a temporary Map
.
Let's have an example of merging newMap
entries into map
and keeping the original values in case of the duplicated antry.
Map<Integer, String> newMap = new HashMap<>();
newMap.put(2, "EVIL VALUE"); // this will NOT be merged into
newMap.put(4, "four"); // this WILL be merged into
newMap.put(5, "five"); // this WILL be merged into
Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
newMap.forEach((k, v) -> map.merge(k, v, (oldValue, newValue) -> oldValue));
map.forEach((k, v) -> System.out.println(k + " " + v));
1 one 2 two 3 three 4 four 5 five
Comments
-
rapadura over 3 years
I need to copy all keys and values from one A HashMap onto another one B, but not to replace existing keys and values.
Whats the best way to do that?
I was thinking instead iterating the keySet and checkig if it exist or not, I would
Map temp = new HashMap(); // generic later temp.putAll(Amap); A.clear(); A.putAll(Bmap); A.putAll(temp);
-
Fabian Barney almost 13 years1.)
entrySet()
returns aSet<Map.Entry>
. 2.) There is no methodcontains(...)
forjava.util.Map
. -
rapadura almost 13 yearsIsnt there a smarter way? Like a Collections utility or so? I hate all the for loops everywhere.
-
Reverend Gonzo almost 13 years@AntonioP: All the for loops everywhere? There's one for loop and it's about as straightforward as you can get.
-
Fabian Barney almost 13 years+1 then, just works when Maps used not with raw type, I think. Got myself a bit fuddled with the Map.Entry :-)
-
rapadura almost 13 years@Reverend Gonzo, ah, elsewhere in the code. :) Wont .putAll replace existing keys and values of a? Ill go with this sense it does seem the most straightforward way.
-
Reverend Gonzo almost 13 yearsIn this case you don't need to do
removeAll
since they'll get overriden anyways. -
Steve Kuo almost 13 years@AntonioP, if you want to do something custom you can't avoid custom code (like looping).
-
brady almost 13 years@Reverend Gonzo: Overwritten by what?
-
brady almost 10 years@luksmir No, that would remove the existing entries that should be preserved.
-
betomoretti over 8 yearsHi! Why mapWithValues.putAll(mapWithAnotherValues) doens't work?
-
brady over 8 years@betomoretti Because if both maps have a value for a key, that would replace the original value with another. That would violate the requirement "not to replace existing keys and values."
-
betomoretti over 8 years@erickson I messed up the requirement. But , in case of that requirement doesn't exists, it's work? Sorry for my English and thanks!
-
betomoretti over 8 years@erickson Well, mapWithValues.putAll(mapWithAnotherValues) void mapWithValues. So, this it's not a good solution. In fact, doesn't work.
-
Louis Wasserman over 8 years@erickson a much more compact Java 8 version:
patch.forEach(target::putIfAbsent)
. -
Simon Baars over 6 yearsI guess this is better for performance than to create a whole new map?
-
user1735921 almost 6 yearscan we have putAllIfAbsent ? thats what I need ?