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

时间:2016-07-20 01:49:57

标签: java java-8 java-stream

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

输入:

"关键-1" :1,2,3,4

"关键-2" :2,3,4,5

"关键-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完成。

-Thanks。

5 个答案:

答案 0 :(得分:13)

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

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:2)

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

transposeMap

假设{{1}}是您要转置的原始地图。 {{1}}会转换您需要的地图。

答案 3 :(得分:2)

你可以通过这种方式实现

假设我有Person和Gender和Age。我希望以这种形式获得它

Map<SEX,List<Person>> 

我会写简单

Map<SEX,List<Person>> map =  personList.stream()

                           .collect(Collectors.groupingBy(Person::getGender));

它会让我得到类似下面的内容(一个键可以反对多个值)

key:MALE
age31sexMALE
age28sexMALE

key:FEMALE
age40sexFEMALE
age44sexFEMALE

答案 4 :(得分:0)

with teeing 您可以分别处理 2 个流中的键和值
从 Java 12 开始

Map<Integer, List<String>> to = from.entrySet().stream()
  .collect(teeing(flatMapping(e -> e.getValue().stream(), toList()),
      flatMapping(e -> (Stream<String>)e.getValue().stream().map(i -> e.getKey()), toList()),
      (k, v) -> {
        return IntStream.range(0, k.size()).boxed().collect(
            groupingBy(i -> k.get(i), mapping(i -> v.get(i), toList())));
      }));