2015-02-19 3 views
3

Я пытаюсь сделать что-то вроде бы несравненно, но пока не повезло. У меня есть список Карта, они происходят из кучки CompletedFutures параллельно, результат затем должен быть соединен. Поскольку ключ на карте уникален, необходимо объединить значения и создать новую карту уникальных ключей, связанных с объединенным списком SomeType. Например:Java 8 stream объединяет карту

map1: ключ1: Sometype1 ключ2: Sometype2

map2 ключ1: Sometype3 ключ2: Sometype4

Желаемый конечный результат: Map3: ключ1: SomeType, Sometype3 ключ2: Sometype2, Sometype4

Я пробовал использовать groupBy и другие методы, но, похоже, большинство из них предполагает работу со списком, а не с картой. джин, поэтому я не смог найти простой способ сделать это.

До сих пор у меня есть что-то вроде:

Map<String, List<Sometype>> volPercent = waitGroup.stream() 
      .map(CompletableFuture::join) 
      .flatMap((e) -> e.entrySet().stream()) 
      .collect(Collectors.groupingBy()); 

Часть Я не уверен, что нужно идти в группировке по частям. Я попытался Map.Entry :: GETKEY, но он не компилируется:

Error:(69, 25) java: incompatible types: inference variable T has incompatible bounds 
equality constraints: com.Sometype 
lower bounds: java.util.Map.Entry<java.lang.String,com.Sometype> 
+3

Пожалуйста построить небольшой работоспособный пример вашей проблемы, то трудно решить только с потоком строки кода. – Keppil

+1

Восходящий материал 'CompletableFuture' немного отвлекает внимание. Для будущих вопросов было бы полезно начать с более явных входов. Но я думаю, что смог понять это. –

ответ

5

Я предполагаю, что вы начинаете с потоком карт:

Stream<Map<String, Sometype>> input = ... ; 

Вы получили довольно далеко с flatmapping и сбора. Тем не менее, код, который вы пробовали,

input.flatMap(map -> map.entrySet().stream()) 
     .collect(Collectors.groupingBy(Map.Entry::getKey)); 

дает вам карту, ключи которого String и чьи значения представляют собой список отображения записей, в частности List<Map.Entry<String,Sometype>>, не List<Sometype>, как вы хотели. Что вам нужно сделать, так это использовать функцию «вниз по течению» коллекционеров после группировки их по ключу. Вы хотите взять каждый Map.Entry и извлечь (сопоставить) его значение, которое равно Sometype. Это делается с помощью коллектора mapping.

Теперь у вас есть несколько экземпляров Sometype для каждого ключа, поэтому вам нужно собрать их в список.Это делается с помощью другого нисходящего коллектора, который собирает их в список. Это делается с помощью знакомого коллектора toList().

Окончательный код выглядит следующим образом:

Map<String, List<Sometype>> result = 
    input.flatMap(map -> map.entrySet().stream()) 
     .collect(groupingBy(Map.Entry::getKey, 
          mapping(Map.Entry::getValue, 
            toList()))); 
2

Проблема заключается в том, что ваша первая попытка (как я понимаю)

Collectors.groupingBy(Map.Entry::getKey) 

собирает в виде Map<K, List<Map.Entry<K, V>>>.

После flatMap у вас есть Stream<Map.Entry<K, V>>, элементы которого groupingBy соответствует K.

Но вы хотите Map<K, List<V>>, так что вы должны использовать groupingBy that takes a downstream collector, а не только классификатор, так что вы можете также отобразить Map.Entry<K, V> в V.

Что-то вроде

Collectors.groupingBy(
    Map.Entry::getKey, 
    Collectors.mapping(
     Map.Entry::getValue, 
     Collectors.toList() 
    ) 
) 
+0

@Feras Vis-a-vis Ваш предыдущий комментарий: вы можете принять любой ответ, наиболее полезный для вас. ;) http://meta.stackexchange.com/a/5235/244864 Также, конечно же, пожалуйста. – Radiodef

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