collectors.groupingby(函数、供应商、收集器)不接受lambda/dosen看不到流化值

swvgeqrz  于 2021-07-12  发布在  Java
关注(0)|答案(2)|浏览(239)

我尝试使用流和收集器对值进行分组。我有一张要拆分的字符串列表。
我的数据:

List<String> stringList = new ArrayList<>();
stringList.add("Key:1,2,3")
stringList.add("Key:5,6,7")

key是map中的键,1,2,3是map中的值
首先,我尝试使用简单的 toMap ```
Map<String, List> outputKeyMap = stringList.stream()
.collect(Collectors.toMap(id -> id.split(":")[0],
id-> Arrays.stream(id.split(":")[1].split(",")).collect(Collectors.toList());

但它不起作用,因为它总是创建同一个键。所以我需要使用 `groupingBy` 功能。

Map<String, List> outputKeyMap = stringList.stream().collect(groupingBy(id -> id.toString().split(":")[0],
TreeMap::new,
Collectors.mapping(id-> Arrays.stream(id.toString().split(":")[1].split(","))
.map(Integer::valueOf)
.collect(Collectors.toSet()))));

但在这个解决方案中,编译器看不到传递到lambda函数中的值,我不知道为什么,因为 `Function` 是作为第一个参数,而且也是成 `Collectors.mapping` . 在此解决方案中,流不起作用。

Collectors.groupingBy (Function<? super T, ? extends K> classifier,
Supplier mapFactory,
Collector<? super T, A, D> downstream)

编辑:为什么groupingby函数不起作用
我忘了在collectors.mapping中添加collectors.toset()作为第二个参数。但后来我收到一套一套,所以这不是我要找的。应该使用flatmapping,但它是在java9中使用的。

Map<String, Set<Set>> collect = stringList.stream()
.collect(groupingBy(id -> id.split(":")[0],
TreeMap::new,
Collectors.mapping(id-> Arrays.stream(id.toString().split(":")[1].split(","),
Collectors.toSet())

h9vpoimq

h9vpoimq1#

你必须使用超负荷的 Collectors.toMap 接受合并函数的:

Map<String, List<Integer>> result = stringList.stream()
        .map(string -> string.split(":"))
        .collect(Collectors.toMap(
                 splitted -> splitted[0],
                 splitted -> Arrays.stream(splitted[1].split(","))
                                   .map(Integer::valueOf)
                                   .collect(Collectors.toCollection(ArrayList::new)),
                 (l1, l2) -> { l1.addAll(l2); return l1; }));

在这里 (l1, l2) -> { l1.addAll(l2); return l1; } 是合并函数。每当发生密钥冲突时,收集器就会调用它。作为 List.addAll 对列表进行变异,我们需要确保创建的第一个列表是可变的,因此 .collect(Collectors.toCollection(ArrayList::new)) 在值Map器函数中。
我还将第一次拆分优化为 Stream.map 在收集之前调用的操作,从而避免多次拆分。
上述解决方案不会从列表中删除重复项。如果你需要的话,你应该收集到 Set 取而代之的是:

Map<String, Set<Integer>> result = stringList.stream()
        .map(string -> string.split(":"))
        .collect(Collectors.toMap(
                 splitted -> splitted[0],
                 splitted -> Arrays.stream(splitted[1].split(","))
                                   .map(Integer::valueOf)
                                   .collect(Collectors.toCollection(LinkedHashSet::new)),
                 (s1, s2) -> { s1.addAll(s2); return s1; }));

请注意 LinkedHashSet 保留插入顺序。

dohp0rv5

dohp0rv52#

假设源代码列表中没有重复的键,则可以 Map<String, List<Integer>> 比如:

Map<String, List<Integer>> result = stringList.stream()
            .collect(toMap(string -> string.split(":")[0],
                    string -> Arrays.stream(string.split(":")[1].split(","))
                            .map(Integer::valueOf)
                            .collect(toList())));

如果你有重复的钥匙,有一种方法 flatMapping 来自java9:

Map<String, List<Integer>> result = stringList.stream()
           .collect(groupingBy(s -> s.split(":")[0], 
                        flatMapping(s -> Arrays.stream(s.split(":")[1].split(","))
                                           .map(Integer::valueOf), 
                        toList())));

输出将包含 Key : {Key=[1, 2, 3, 5, 6, 7]}

相关问题