1 回答
TA贡献1859条经验 获得超6个赞
回答这个问题的话,我们可以先来看看为啥会出现Map<String, List<List<String>>>的结果,这要从Collectors.groupingBy的设计语义来说了,它代表把流的数据按照一定规则进行归类分组,并要求提供同一组的数据怎么进行收集的方法,所以这就是Collectors.groupingBy两个参数的含义
那题主第一个参数写的是Condition::getCondName,代表流的Condition按照其condName属性进行分组,分组之后,同一组的Condition如何处理,这里题主用的Collectors.mapping(Condition::getCondValue, Collectors.toList())),mapping代表映射转换,这里有点类似分组,Collectors.mapping第一个参数把流的Condition转化为List<String>,此时流里就是List<String>,再经过第二个参数Collectors.toList(),哦豁,当然最后结果就是List<List<String>>
这里题主得不到答案的原因就是Collectors.mapping的第二个参数没有写对,我这里想到三种方式
第一种:还是用Collectors.mapping,类似题主提到的再遍历一遍,哈哈
Map<String, List<String>> collect = conditions.stream()
.collect(Collectors.groupingBy(Condition::getCondName,
Collectors.mapping(Condition::getCondValue,
Collectors.collectingAndThen(Collectors.toList(), lists -> lists.stream().flatMap(List::stream).collect(Collectors.toList())))));
这里Collectors.mapping的第二个参数用了Collectors.collectingAndThen,从名字就看得出来,收集好了之后再做什么事...第一个参数当然还是按照Collectors.toList(),收集到之后,第二个参数再把List遍历一次,压平后再组成List
emmm,我也不太喜欢这种,不过只是引出了哈collectingAndThen,说不定以后题主可以用到
第二种:也还是用Collectors.mapping,不过这次第二个参数用Collectors.reducing
Map<String, List<String>> collect2 = conditions.stream()
.collect(Collectors.groupingBy(Condition::getCondName,
Collectors.mapping(Condition::getCondValue,
Collectors.reducing(new ArrayList<>(), (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList())))));
这里的Collectors.reducing就是数据的聚合,正好也符合当前的场景,当流里的数据由Condition转化为List<String>时,我们就是要找到一种合并不同List<String>的方法,所以这里用到这个聚合方法Collectors.reducing,第一个参数是起始值,第二个参数代表怎么合并两个list
第二个方法要好一点,不过这里我还想到第三个方法
第三种:不用Collectors.groupingBy,而采用Collectors.toMap
Map<String, List<String>> collect1 = conditions.stream().collect(
Collectors.toMap(Condition::getCondName, Condition::getCondValue, (c1, c2) -> Stream.concat(c1.stream(), c2.stream()).collect(Collectors.toList())));
第三种方式感觉要比前两种简单点,但是这是巧用了哈toMap方法,toMap方法一般使用在数据能够有一种一对一的关系时才用,大多数的时候我们一般也只使用两个参数的方法,即传入怎么获取map的key和怎么获取map的value的两个Function,因为一般情况下,业务上可以保证数据是具有一对一的关系的,如果只是调用两参方法,但是实际使用过程中,确实出现了一对多的情况,那么这时候调用toMap两参方法是会报错的,因此就有了toMap这个三参方法,第三个参数代表怎么合并同一个key的value值,所以到了这里就跟第二种方法的思路差不多了,合并两个集合即可
以上就是我的回答,仅供参考
对了,再加一点,我一般是不太喜欢在流里写过长的lambda表达式的,因为流里是要体现当前流程的,不是烂七八糟的都往里噻,所以第三种方式,最后的集合合并,最好还是写成一个BinaryOperator,毕竟现在方法也可以是一种参数或者属性了嘛
public static final BinaryOperator<List<String>> listMergeMethod = (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(Collectors.toList());
Map<String, List<String>> collect1 = conditions.stream().collect(
Collectors.toMap(Condition::getCondName, Condition::getCondValue, listMergeMethod));
这样我感觉要顺点。。。
添加回答
举报
