4

Anybody knows how to merge with Java 8 two maps of this type?

Map<String,  List<String>> map1--->["a",{1,2,3}]
Map<String,  List<String>> map2--->["a",{4,5,6}]

And obtain as result of the merge

Map<String,  List<String>> map3--->["a",{1,2,3,4,5,6}]

I´m looking for a non verbose way if exist. I know how to do it in the old fashion way.

Regards.

Alexis C.
  • 91,686
  • 21
  • 171
  • 177
paul
  • 12,873
  • 23
  • 91
  • 153
  • 1
    http://stackoverflow.com/questions/8795945/merging-two-maps/25152991#25152991 – Alex - GlassEditor.com Feb 25 '16 at 22:09
  • is a map of list, is not the same. I've seen those post before – paul Feb 25 '16 at 22:12
  • in my case is even more complicated since the map is created inside an iterator, so I need to merge the last map created with the new one in every iteration. Thanks but still dont see how can works in my example. Maybe can you provide an example? I really dont seen it. Thanks!!! – paul Feb 25 '16 at 22:20
  • 2
    If you're using Guava, and have `ListMultimap`s, then this is just `putAll`. – Louis Wasserman Feb 25 '16 at 22:20

3 Answers3

6

The general idea is the same as in this post. You create a new map from the first map, iterate over the second map and merge each key with the first map thanks to merge(key, value, remappingFunction). In case of conflict, the remapping function is applied: in this case, it takes the two lists and merges them; if there is no conflict, the entry with the given key and value is put.

Map<String, List<String>> mx = new HashMap<>(map1);
map2.forEach((k, v) -> mx.merge(k, v, (l1, l2) -> {
    List<String> l = new ArrayList<>(l1);
    l.addAll(l2);
    return l;
}));
Community
  • 1
  • 1
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • Is the less verbose code that I found, so I´ll take it! ;) thank you! – paul Feb 25 '16 at 22:26
  • 3
    An alternative merge function would be `(l1, l2) -> Stream.concat(l1.stream(),l2.stream()).collect(toList())`. That’s the simplest Java has so far (without 3rd party libraries). – Holger Feb 26 '16 at 09:40
  • That´s reduce the verbose on the merge function, thanks!! – paul Feb 26 '16 at 10:10
  • 2
    @paul It does reduce the verbosity but is a bit more complex (since it creates streams pipelines). – Tunaki Feb 26 '16 at 10:20
  • more than complexity it´s matter to me the speed. I guess is true that is less verbose but more expensive – paul Feb 26 '16 at 10:30
  • If performance matters, the better merge function would be `(l1, l2) -> { List l = new ArrayList<>(l1.size()+l2.size()); l.addAll(l1); l.addAll(l2); return l; }` to ensure proper initial capacity. But the question was about “non verbose way”… – Holger Feb 29 '16 at 13:52
1

You could try this, which gradually flattens the structure until you have a stream of tuples of the maps keys versus the lists values:

Map<K,List<V>> result = Stream.of(map1,map2) // Stream<Map<K,List<V>>>
    .flatMap(m -> m.entrySet().stream()) // Stream<Map.Entry<K,List<V>>>
    .flatMap(e -> e.getValue().stream() // Inner Stream<V>...
            .map(v -> new AbstractMap.SimpleImmutableEntry<>(e.getKey(), v))) 
    // ...flatmapped into an outer Stream<Map.Entry<K,V>>>
    .collect(Collectors.groupingBy(e -> e.getKey(), Collectors.mapping(e -> e.getValue(), Collectors.toList())));

Another option would avoid the internal streaming of the lists by using Collectors.reducing() as a second parameter of groupingBy, I guess. However, I would consider the accepted answer first

user2418306
  • 2,352
  • 1
  • 22
  • 33
Javier Martín
  • 2,537
  • 10
  • 15
1

You have to use Set instead of List and can do it like this:

Map<String, Set<String>> map1--->["a",{1,2,3}]
Map<String, Set<String>> map2--->["a",{4,5,6}]

map1.forEach((k, v) -> v.addAll(map2.get(k) == null : new HashSet<> ? map2.get(k)));
Oussama Zoghlami
  • 1,660
  • 17
  • 24
  • Besides assuming mutable collections and not handling potential absence of the key in the second map, I don’t see why this should require `Set`s. It would be exactly the same for `List`s. – Holger Feb 26 '16 at 09:35
  • because with lists, you will have duplicate values – Oussama Zoghlami Feb 26 '16 at 10:24