如何使用 Java 8 功能 API 将 Map<String, List<List<String>>> 转换为 Map<String, List<String>>?

问题描述 投票:0回答:3

我有一堂这样的课:

class: {
   id: "",
   sub: [{
       type: 1,
       value: ""
   }]
}

现在,我想先通过 id 对班级进行分组:

class.stream().collect(Collectors.groupingBy(class::id))

然后我想要将子值平坦化为

List<String>
。我有以下内容:

class.stream().collect(Collectors.groupingBy(class::id,
  Collectors.mapping(e ->
    e.sub().stream()
      .filter(v -> v.type().equals(1))
       .map(sub::value),
    Collectors.toList()
  )))

这会返回一个

Map<String, List<List<String>>>

如何使用 Java 8 功能 API 将

Map<String, List<List<String>>>
转换为
Map<String, List<String>>

java java-stream
3个回答
1
投票

您可以使用

Map
收集器按键分组并合并值。

示例(Java 14 及以上版本):

class Test {

    // sample data types
    record Sub ( int type, String value ){}
    record Clazz (String id, List<Sub> sub){}

    public static void main(String[] args)
    {
        // sample data
        List<Clazz> classes = List.of(
            new Clazz("id1",List.of(new Sub(1,"A"),new Sub(2,"B"))),
            new Clazz("id2",List.of(new Sub(3,"C"),new Sub(4,"D"))),
            new Clazz("id1",List.of(new Sub(5,"E"),new Sub(6,"A")))
        );

        Map<String, List<String>> map = classes.stream()
            .collect(Collectors.toMap(
                // key for new map: c.id
                c -> c.id,
                
                // value for new map: c.sub[].value as a list
                c -> c.sub.stream().map(s -> s.value).toList(),
                
                // duplicate value merging (grouping) : merge two value lists, no duplicates
                (v1, v2) -> Stream.concat(v1.stream(), v2.stream()).distinct().toList()
            ));

        // print resulting data
        map.forEach((k,v) -> System.out.println(k + "\t->\t" + String.join(",", v)));
    }
}

输出:

id2 ->  C,D
id1 ->  A,B,E

0
投票

就像@Sametcey建议你可以使用

flatMap

每当你遇到使用嵌套列表的东西时(就像你的
Map<String, List<List>>
,但可以在更深层次上使用它,如
Map<String, List<List<List>>>
flatMap
会帮助你就这样。

它将把您的流转换为单个扁平流。换句话说:您可以访问和操作的一个列表。


0
投票

查看示例代码,您似乎想通过唯一 ID 对元素进行分组,映射到所有

sub
值,其中
type
= 1。这可以使用下游 Collectors.groupingBy(classifier, downstream)
 使用 
Collector
 来实现它映射并过滤匹配的 
sub
值。

record Sub(int type, String value) { }
record Clazz(String id, List<Sub> sub) { }

List<Clazz> classes = List.of( /* ... */ );

Map<String, List<String>> map = classes.stream()
        .collect(Collectors.groupingBy(
                Clazz::id,
                Collectors.collectingAndThen(Collectors.toList(),
                        l -> l.stream().flatMap(c -> c.sub().stream())
                                .filter(s -> s.type() == 1)
                                .map(Sub::value)
                                .toList())));

Collectors.collectingAndThen
首先收集与给定 ID 与
List<Sub>
匹配的所有值。然后,它流过该列表,过滤并映射到值,以给出类型 1 的
List<String>
元素的
value
属性的
sub

例如:

List<Clazz> classes = List.of(
        new Clazz("1", List.of(new Sub(1, "1A"), new Sub(2, "1B"), new Sub(1, "1C"))),
        new Clazz("2", List.of(new Sub(3, "2A"), new Sub(1, "2B"), new Sub(1, "2C"))),
        new Clazz("1", List.of(new Sub(5, "3A"), new Sub(1, "3B"), new Sub(6, "3C")))
);

结果:

{1=[1A, 1C, 3B], 2=[2B, 2C]}
© www.soinside.com 2019 - 2024. All rights reserved.