Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I combine two HashMap objects containing the same types?

Tags:

java

hashmap

People also ask

How can I combine two HashMap objects containing the different types?

Assuming that both maps contain the same set of keys, and that you want to "combine" the values, the thing you would be looking for is a Pair class, see here for example. You simply iterate one of the maps; and retrieve values from both maps; and create a Pair; and push that in your result map.

How do you combine hash maps?

Merge Two HashMaps Ignoring Duplicate Keys This one is a simple solution. Use firstMap. putAll(secondMap) method that copies all of the mappings from the secondMap to firstMap. As we know hashmap does not allow duplicate keys.

Can a HashMap have two of the same keys?

Duplicates: HashSet doesn't allow duplicate values. HashMap stores key, value pairs and it does not allow duplicate keys.

What is merge in HashMap?

The Java HashMap merge() method inserts the specified key/value mapping to the hashmap if the specified key is already not present. If the specified key is already associated with a value, the method replaces the old value with the result of the specified function.


map3 = new HashMap<>();

map3.putAll(map1);
map3.putAll(map2);

If you know you don't have duplicate keys, or you want values in map2 to overwrite values from map1 for duplicate keys, you can just write

map3 = new HashMap<>(map1);
map3.putAll(map2);

If you need more control over how values are combined, you can use Map.merge, added in Java 8, which uses a user-provided BiFunction to merge values for duplicate keys. merge operates on individual keys and values, so you'll need to use a loop or Map.forEach. Here we concatenate strings for duplicate keys:

map3 = new HashMap<>(map1);
for (Map.Entry<String, String> e : map2.entrySet())
    map3.merge(e.getKey(), e.getValue(), String::concat);
//or instead of the above loop
map2.forEach((k, v) -> map3.merge(k, v, String::concat));

If you know you don't have duplicate keys and want to enforce it, you can use a merge function that throws an AssertionError:

map2.forEach((k, v) ->
    map3.merge(k, v, (v1, v2) ->
        {throw new AssertionError("duplicate values for key: "+k);}));

Taking a step back from this specific question, the Java 8 streams library provides toMap and groupingBy Collectors. If you're repeatedly merging maps in a loop, you may be able to restructure your computation to use streams, which can both clarify your code and enable easy parallelism using a parallel stream and concurrent collector.


One-liner using Java 8 Stream API:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue))

Among the benefits of this method is ability to pass a merge function, which will deal with values that have the same key, for example:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))

Java 8 alternative one-liner for merging two maps:

defaultMap.forEach((k, v) -> destMap.putIfAbsent(k, v));

The same with method reference:

defaultMap.forEach(destMap::putIfAbsent);

Or idemponent for original maps solution with third map:

Map<String, Integer> map3 = new HashMap<String, Integer>(map2);
map1.forEach(map3::putIfAbsent);

And here is a way to merge two maps into fast immutable one with Guava that does least possible intermediate copy operations:

ImmutableMap.Builder<String, Integer> builder = ImmutableMap.<String, Integer>builder();
builder.putAll(map1);
map2.forEach((k, v) -> {if (!map1.containsKey(k)) builder.put(k, v);});
ImmutableMap<String, Integer> map3 = builder.build();

See also Merge two maps with Java 8 for cases when values present in both maps need to be combined with mapping function.


If you don't need mutability for your final map, there is Guava's ImmutableMap with its Builder and putAll method which, in contrast to Java's Map interface method, can be chained.

Example of use:

Map<String, Integer> mergeMyTwoMaps(Map<String, Integer> map1, Map<String, Integer> map2) {
  return ImmutableMap.<String, Integer>builder()
      .putAll(map1)
      .putAll(map2)
      .build();
}

Of course, this method can be more generic, use varargs and loop to putAll Maps from arguments etc. but I wanted to show a concept.

Also, ImmutableMap and its Builder have few limitations (or maybe features?):

  • they are null hostile (throw NullPointerException - if any key or value in map is null)
  • Builder don't accept duplicate keys (throws IllegalArgumentException if duplicate keys were added).

HashMap has a putAll method.

http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html