2016-02-25 3 views
4

Кто-нибудь знает, как слиться с Java 8 двумя картами этого типа?Объединить две карты значений значений

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

и получить в результате слияния

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

I'm ищет, не многословной образом, если существует. Я знаю, как это сделать по-старому.

С уважением.

+1

http://stackoverflow.com/questions/8795945/merging-two-maps/ 25152991 # 25152991 – Alex

+0

- это карта списка, не то же самое. Я видел эти сообщения до – paul

+0

в моем случае еще сложнее, так как карта создается внутри итератора, поэтому мне нужно объединить последнюю карту, созданную с новой, на каждой итерации. Спасибо, но не вижу, как это работает в моем примере. Может быть, вы можете привести пример? Я действительно не видел его. Благодаря!!! – paul

ответ

6

Общая идея такая же, как и в this post. Вы создаете новую карту с первой карты, перебираете вторую карту и объединяете каждый ключ с первой картой благодаря merge(key, value, remappingFunction). В случае конфликта применяется функция переназначения: в этом случае она берет два списка и объединяет их; если нет конфликта, вводится запись с заданным ключом и значением.

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; 
})); 
+0

Является ли менее сложный код, который я нашел, поэтому я возьму его! ;) Спасибо! – paul

+2

Альтернативной функцией слияния будет '(l1, l2) -> Stream.concat (l1.stream(), l2.stream()). Collect (toList())'. Это простейшая Java до сих пор (без сторонних библиотек). – Holger

+0

Это уменьшает подробные сведения о функции слияния, спасибо! – paul

1

Вы могли бы попробовать это, постепенно разглаживает структуру до тех пор, пока есть поток кортежей отображений ключей в сравнении значений списков:

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()))); 

Другой вариант позволит избежать внутренней потоковой передачи списков с помощью Коллекторы .reducing() как второй параметр группировкиBy, я думаю. Тем не менее, я бы сначала принял принятый ответ

1

Вы должны использовать Set вместо Список и может сделать это следующим образом:

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))); 
+0

Не будет работать для списков фиксированного размера. – user2418306

+0

Кроме того, предполагая изменчивые коллекции и не обрабатывая потенциальное отсутствие ключа во второй карте, я не понимаю, почему это должно требовать 'Set'. Это было бы точно так же для 'List'. – Holger

+0

, потому что со списками вы будете иметь повторяющиеся значения –

Смежные вопросы