Java使用groupingBy分组数据乱序问题解决方案 - Go语言中文社区

Java使用groupingBy分组数据乱序问题解决方案


业务背景

假设当前有一个对学生进行各方面评价的对象,评价包括考察模块、考察点、评价备注。字段关系为,同一模块包含多个考察点,每个考察点有一个评价备注。
对象代码如下
/**
 * 评价信息对象
 */
@Data
@AllArgsConstructor
class Evaluation {

    /**
     * 考查模块
     */
    private String inspectionModule;

    /**
     * 考察点
     */
    private String inspectionPoint;

    /**
     * 评价备注
     */
    private String remark;
}

接下来我们做一些测试数据,看起来会直观一些
    public static void main(String[] args) {
        List<Evaluation> list = new ArrayList<>() {{
            add(new Evaluation("课上表现", "专注力", "上课的时候很专注"));
            add(new Evaluation("课上表现", "表达能力", "表达能力还可以"));
            add(new Evaluation("逻辑思维", "清晰度", "思路比较清晰"));
            add(new Evaluation("逻辑思维", "敏捷程度", "反应有点迟钝"));
            add(new Evaluation("课后作业", "卷面分", "卷面干净整节"));
            add(new Evaluation("课后作业", "正确率", "大约90%的样子"));
        }};
        list.forEach(System.out::println);
    }
这里我们把创建的测试对象集合打印出来(控制台打印信息如下)

在这里插入图片描述

看图我们可以更加直观地看到我们数据是1个模块2个考察点这样的关系,这个时候,我们想要按照考察模块对数据进行分组。很简单,使用stream中的groupingBy即可。

技术实现

我们直接上代码
    public static void main(String[] args) {
        List<Evaluation> list = new ArrayList<>() {{
            add(new Evaluation("课上表现", "专注力", "上课的时候很专注"));
            add(new Evaluation("课上表现", "表达能力", "表达能力还可以"));
            add(new Evaluation("逻辑思维", "清晰度", "思路比较清晰"));
            add(new Evaluation("逻辑思维", "敏捷程度", "反应有点迟钝"));
            add(new Evaluation("课后作业", "卷面分", "卷面干净整节"));
            add(new Evaluation("课后作业", "正确率", "大约90%的样子"));
        }};
        list.forEach(System.out::println);
        Map<String, List<Evaluation>> map = list.stream().collect(Collectors.groupingBy(Evaluation::getInspectionModule));
        map.forEach((s, evaluations) -> System.out.println(s + ": " + evaluations));
    }
运行结果是怎样的呢?(控制台打印信息如下)

在这里插入图片描述

数据确实根据考察模块进行了聚合,但是它的顺序却不是按照我们事先安排好的顺序,那么原因是什么呢?我们在数据聚合成map之后,打印一下这个map的信息即可知道原因。
System.out.println(map.getClass().getSimpleName());
打印出来的信息是“HashMap”,原因找到了,因为聚合后的数据是用HashMap来收集的,所以打乱了原本的顺序。

在这里插入图片描述

查看源码我们也能看出来,groupingBy默认使用HashMap来收集数据。因此我们只需要把HashMap换成LinkedHashMap即可解决这个问题。

在这里插入图片描述

通过阅读源码我们也能看到,groupingBy本身也是支持我们去自定义一个Map实例去收集数据的。

代码优化

    public static void main(String[] args) {
        List<Evaluation> list = new ArrayList<>() {{
            add(new Evaluation("课上表现", "专注力", "上课的时候很专注"));
            add(new Evaluation("课上表现", "表达能力", "表达能力还可以"));
            add(new Evaluation("逻辑思维", "清晰度", "思路比较清晰"));
            add(new Evaluation("逻辑思维", "敏捷程度", "反应有点迟钝"));
            add(new Evaluation("课后作业", "卷面分", "卷面干净整节"));
            add(new Evaluation("课后作业", "正确率", "大约90%的样子"));
        }};
        list.forEach(System.out::println);
        Map<String, List<Evaluation>> map = list.stream().collect(Collectors.groupingBy(Evaluation::getInspectionModule, LinkedHashMap::new, Collectors.toList()));
        map.forEach((s, evaluations) -> System.out.println(s + ": " + evaluations));
    }
运行结果如下

在这里插入图片描述

Finish

题外话

优化聚合后的数据,增强数据可读性
    public static void main(String[] args) {
        //创建测试数据
        List<Evaluation> list = new ArrayList<>() {{
            add(new Evaluation("课上表现", "专注力", "上课的时候很专注"));
            add(new Evaluation("课上表现", "表达能力", "表达能力还可以"));
            add(new Evaluation("逻辑思维", "清晰度", "思路比较清晰"));
            add(new Evaluation("逻辑思维", "敏捷程度", "反应有点迟钝"));
            add(new Evaluation("课后作业", "卷面分", "卷面干净整节"));
            add(new Evaluation("课后作业", "正确率", "大约90%的样子"));
        }};
        //打印集合
        list.forEach(System.out::println);
        //根据考察模块进行数据聚合
        Map<String, List<Evaluation>> map = list.stream().collect(Collectors.groupingBy(Evaluation::getInspectionModule, LinkedHashMap::new, Collectors.toList()));
        //打印map实现类
        System.out.println(map.getClass().getSimpleName());
        //打印聚合后的数据
        map.forEach((s, evaluations) -> System.out.println(s + ": " + evaluations));
        //数据可读性优化
        StringBuilder msg = new StringBuilder();
        map.forEach((s, evaluations) -> {
            msg.append(s).append(":rn");
            evaluations.forEach(inspectDetail -> msg.append(inspectDetail.getInspectionPoint()).append(": ")
                    .append(inspectDetail.getRemark()).append("rn"));
        });
        System.out.println(msg);
    }
运行结果如下

在这里插入图片描述

完整的代码片段在这里? 码云代码片段
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_31226223/article/details/100145232
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-01 22:21:06
  • 阅读 ( 1294 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢