相关文章推荐
豪情万千的米饭  ·  Python 删除字符串首尾的空格 | ·  5 天前    · 
聪明的红薯  ·  Java代码实现sha256加密_java ...·  4 天前    · 
刚失恋的烤面包  ·  String.CompareToIgnore ...·  2 天前    · 
神勇威武的梨子  ·  获取Android手机CPU类型 ...·  2 天前    · 
儒雅的热带鱼  ·  android ...·  2 天前    · 
机灵的盒饭  ·  全球和中国电池级碳酸锂市场发展调研与前景研究 ...·  10 月前    · 
老实的显示器  ·  天上掉下个林妹妹是什么意思???·  1 年前    · 
爱笑的西红柿  ·  温州第二外国语学校初中部学费是多少,外国语只 ...·  1 年前    · 
近视的卡布奇诺  ·  故事:三生往事说不清,小刀子奈何桥边等情郎, ...·  1 年前    · 
独立的松鼠  ·  刘心文:云度3.5万辆销量目标背后的秘密武器 ...·  1 年前    · 
Code  ›  求助,关于java8 Collectors的groupingBy和mapping -
string
https://segmentfault.com/q/1010000016707409
满身肌肉的火柴
1 年前
segmentfault segmentfault
注册登录
问答 博客 标签 活动
发现
✓ 使用“Bing”搜本站 使用“Google”搜本站 使用“百度”搜本站 站内搜索
注册登录
  1. 首页
  2. 问答
  3. java
  4. 问答详情

求助,关于java8 Collectors的groupingBy和mapping

头像
codingaperoid
12 1 1 4
发布于
2018-10-17
  • 小弟尝试将一段如下json读到一个Map<String, List<String>>中,map

的key为condName,map的value为condValue

  • 现在用stream结合Collectors的groupingBy和toList方法,将List<Condition>转成了Map<String, List<Condition>>
  • 然后尝试通过mapping方法将List<Condition>映射为List<String>时发现无从下手。。。几次尝试后得到了一个Map<String, List<List<String>>>,多了一层List
  • 想去掉这一层List,如果再遍历一遍又感觉不太优雅
  • 求助各位有什么思路吗,最好是通过mapping一次得到想要的结果
  • 不胜感激!
  • 问题出现的环境背景及自己尝试过哪些方法

    "condition": [ "condName": "name1", "condValue": [ "val11", "val12" "condName": "name2", "condValue": [ "val21" "condName": "name3", "condValue": [ "val31", "val32", "val33" "total": 3
    @Data
    public class Request {
        private List<Condition> condition;
        private Long total;
    
    @Data
    public class Condition {
        private String condName;
        private List<String> condValue;
    

    转换方法(读取json和转成Request对象的代码省略。。。):

    String json = getContent();
    try {
        List<Condition> conditions = deseriliaze(json).getCondition();
        Map<String, List<Condition>> map1 = conditions.stream().collect(Collectors.groupingBy(Condition::getCondName));
        Map<String, List<List<String>>> map2 = conditions.stream().collect(Collectors.groupingBy(Condition::getCondName, Collectors.mapping(Condition::getCondValue, Collectors.toList())));
    } catch (Exception e) {
        e.printStackTrace();
    

    你期待的结果是什么?实际看到的错误信息又是什么?

    • map1:
    {name3=[Condition(condName=name3, condValue=[val31, val32, val33])], name2=[Condition(condName=name2, condValue=[val21])], name1=[Condition(condName=name1, condValue=[val11, val12])]}
    • map2:
    {name3=[[val31, val32, val33]], name2=[[val21]], name1=[[val11, val12]]}
    java stream group-by json
    阅读 15.4k
    1 个回答
    得票 最新
    头像
    imango
    3k 3 14 15
    发布于
    2018-10-17
    更新于
    2018-10-17
    ✓ 已被采纳

    回答这个问题的话,我们可以先来看看为啥会出现 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 值,所以到了这里就跟第二种方法的思路差不多了,合并两个集合即可

    以上就是我的回答,仅供参考

     
    推荐文章
    豪情万千的米饭  ·  Python 删除字符串首尾的空格 |
    5 天前
    聪明的红薯  ·  Java代码实现sha256加密_java sha256
    4 天前
    刚失恋的烤面包  ·  String.CompareToIgnoreCase(String) Method (Java.Lang) | Microsoft Learn
    2 天前
    神勇威武的梨子  ·  获取Android手机CPU类型 ARM、ARMV7、NEON_arm获取cpuid
    2 天前
    儒雅的热带鱼  ·  android 比较字符串_mob64ca12dbdb81的技术博客_
    2 天前
    机灵的盒饭  ·  全球和中国电池级碳酸锂市场发展调研与前景研究报告2024年
    10 月前
    老实的显示器  ·  天上掉下个林妹妹是什么意思???
    1 年前
    爱笑的西红柿  ·  温州第二外国语学校初中部学费是多少,外国语只要是哪个国家的语音_百度知道
    1 年前
    近视的卡布奇诺  ·  故事:三生往事说不清,小刀子奈何桥边等情郎,真相却是那么残酷|阎王|罗烟|魂魄|地府|心上人_网易订阅
    1 年前
    独立的松鼠  ·  刘心文:云度3.5万辆销量目标背后的秘密武器_凤凰网汽车_凤凰网
    1 年前
    今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
    删除内容请联系邮箱 2879853325@qq.com
    Code - 代码工具平台
    © 2024 ~ 沪ICP备11025650号