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。 transposeMap
将具有您需要的转置地图。
你可以用这种方式实现
假设我有Person和Gender和Age。 我希望以这种forms得到它
Map>
我会写简单的
Map> map = personList.stream() .collect(Collectors.groupingBy(Person::getGender));
它会让我得到类似下面的东西(一个键对多个值)
key:MALE age31sexMALE age28sexMALE key:FEMALE age40sexFEMALE age44sexFEMALE