Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java8 streams : Transpose map with values as list

I have map with key as String and value as List. List can have 10 unique values. I need to convert this map with key as Integer and value as List. Example as below :

Input :

"Key-1" : 1,2,3,4

"Key-2" : 2,3,4,5

"Key-3" : 3,4,5,1

Expected output :

1 : "Key-1","Key-3"

2 : "Key-1","Key-2"

3 : "Key-1", "Key-2", "Key-3"

4 : "Key-1", "Key-2", "Key-3"

5 : "Key-2", "Key-3"

I am aware that using for loops i can achieve this but i needed to know can this be done via streams/lamda in java8.

-Thanks.

like image 580
KhajalId Avatar asked Jul 20 '16 01:07

KhajalId


2 Answers

An idea could be to generate all value-key pairs from the original map and then group the keys by these values:

import java.util.AbstractMap.SimpleEntry;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;

...

Map<Integer, List<String>> transposeMap =
    map.entrySet()
       .stream()
       .flatMap(e -> e.getValue().stream().map(i -> new SimpleEntry<>(i, e.getKey())))
       .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));
like image 128
Alexis C. Avatar answered Sep 28 '22 04:09

Alexis C.


Alexis’ answer contains the general solution for this kind of task, using flatMap and a temporary holder for the combination of key and flattened value. The only alternative avoiding the creation of the temporary holder objects, is to re-implement the logic of the groupingBy collector and inserting the loop over the value list logic into the accumulator function:

Map<Integer, List<String>> mapT = map.entrySet().stream().collect(
    HashMap::new,
    (m,e) -> e.getValue().forEach(
                 i -> m.computeIfAbsent(i,x -> new ArrayList<>()).add(e.getKey())),
    (m1,m2) -> m2.forEach((k,v) -> m1.merge(k, v, (l1,l2)->{l1.addAll(l2); return l1;})));
like image 30
Holger Avatar answered Sep 28 '22 05:09

Holger