Collectors.groupingBy(功能,供应商,收集器)不接受lambda/看不到流式传输的值 [英] Collectors.groupingBy (Function, Supplier, Collector) doesn't accept lambda / dosen't see streamed values

查看:446
本文介绍了Collectors.groupingBy(功能,供应商,收集器)不接受lambda/看不到流式传输的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用流和收集器对值进行分组. 我有要拆分的String列表.

I tried to group values using streams and Collectors. I have list of String which I have to split.

我的数据:

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

是地图中的键, 1,2,3 是地图中的值

Key is a key in map and 1,2,3 are a values in map

首先,我尝试使用简单的toMap

First I have tried using simple toMap

Map<String, List<Integer>> outputKeyMap = stringList.stream()
 .collect(Collectors.toMap(id -> id.split(":")[0], 
          id-> Arrays.stream(id.split(":")[1].split(",")).collect(Collectors.toList());

,但是它不能正常工作,因为它总是创建相同的密钥.所以我需要使用groupingBy函数.

but it dosen't work because it always create the same key. So I need to use groupingBy function.

Map<String, List<Integer>> 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中.在此解决方案中,流不起作用.

But in this solution compiler dosen't see values passed into lambda functions, and I don't why because Function is as first parameter, and also into Collectors.mapping. In this solution stream doesn't work.

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

为什么groupingBy功能不起作用

我忘记在Collectors.mapping中添加Collectors.toSet()作为第二个参数.但是后来我收到Set in Set,所以这不是我想要的.应该使用flatMapping,但是它在Java9中.

I forgot to add Collectors.toSet() in Collectors.mapping as the second parameter. But then I receive Set in Set so it wasn't what am I looking for. There should be used flatMapping but it is in Java9.

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

推荐答案

您必须使用

此处(l1, l2) -> { l1.addAll(l2); return l1; }是合并功能.每当有按键碰撞时,收集器都会调用它.当List.addAll更改列表时,我们需要确保创建的第一个列表是可变的,因此在值映射器函数中使用.collect(Collectors.toCollection(ArrayList::new)).

Here (l1, l2) -> { l1.addAll(l2); return l1; } is the merge function. It will be called by the collector whenever there's a key collision. As List.addAll mutates the list, we need to make sure that the first list that is created is mutable, hence the usage of .collect(Collectors.toCollection(ArrayList::new)) in the value mapper function.

我还将第一次拆分优化为在收集之前调用的Stream.map操作,从而避免了多次拆分.

I've also optimized the first splitting to a Stream.map operation that is called before collecting, thus avoiding splitting more than once.

上述解决方案不会从列表中删除重复项.如果需要,您应该改为收集Set:

The above solution doesn't remove duplicates from the lists. If you need that, you should collect to a Set instead:

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保留插入顺序.

Note that LinkedHashSet preserves insertion order.

这篇关于Collectors.groupingBy(功能,供应商,收集器)不接受lambda/看不到流式传输的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆