Java8流:将值转换为列表的转置映射

我有键映射为String,值为List。 列表可以有10个唯一值。 我需要将此映射转换为键为Integer,将值转换为List。 示例如下:

输入:

“关键1”:1,2,3,4

“Key-2”:2,3,4,5

“Key-3”:3,4,5,1

预期产量:

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”

我知道使用for循环我可以实现这一点,但我需要知道这可以通过java8中的streams / lamda完成。

-谢谢。

一个想法可能是从原始地图生成所有价值密钥对,然后按这些值对密钥进行分组:

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

Alexis的回答包含了这类任务的一般解决方案,使用flatMap和临时持有者来组合键值和展平值。 避免创建临时holder对象的唯一选择是重新实现groupingBy收集器的逻辑, 并将值列表逻辑上的循环插入到accumulator函数中:

 Map> 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;}))); 

它有点可怕(我通常会尝试将其分解以使其更具可读性)但您可以这样做:

 Map> transposeMap = new HashMap<>(); map.forEach((key, list) -> list.stream().forEach( elm -> transposeMap.put(elm, transposeMap.get(elm) == null ? Arrays.asList(key) : (Stream.concat(transposeMap.get(elm).stream(), Arrays.asList(key).stream()).collect(Collectors.toList()))))); 

假设Map> map是您想要转置的原始Map。 transposeMap将具有您需要的转置地图。

你可以用这种方式实现

假设我有Person和Gender和Age。 我希望以这种forms得到它

 Map> 

我会写简单的

 Map> map = personList.stream() .collect(Collectors.groupingBy(Person::getGender)); 

它会让我得到类似下面的东西(一个键对多个值)

 key:MALE age31sexMALE age28sexMALE key:FEMALE age40sexFEMALE age44sexFEMALE