• One bite of Stream(8)


    Group

    我们经常有这样的一些需求,将一组数据按照某个或某几个属性进行分组,属性相同的元素存储在一个List中,属性不同的元素存储在不同的List中。

    1. Map> dishesByType = menu.stream()
    2. .collect(groupingBy(Dish::getType));

    通过groupingBy()方法,可以根据给定的属性进行分组,得到一个Map,Map的Key就是唯一的Type,Map的values就是Type相同的所有Dish的List。

    我们把Dish::getType称为分类方法 / 分组方法。 

    自定义分组方式

    在某些场景下,函数引用并不能得到提供,因此我们可以自定义分组方法:

    1. public enum CaloricLevel {
    2. DIET,
    3. NORMAL,
    4. FAT
    5. }

    首先,我们定义了一个Enum,用于表示不同的组。

    1. Map> group = menu.stream()
    2. .collect(groupingBy(dish -> {
    3. if (dish.getCalories() <= 400)
    4. return CaloricLevel.DIET;
    5. else if (dish.getCalories() <= 700)
    6. return CaloricLevel.NORMAL;
    7. else
    8. return CaloricLevel.FAT;
    9. }));

    然后根据不同的规则,返回了不同的枚举值,这样就可以按照自己的意愿进行分组了。

    多分组

    我们也会遇到类似的场景:先按A分组,在内部按B分组。

    1. Map>> dishesByTypeCaloricLevel =
    2. menu.stream()
    3. .collect(groupingBy(Dish::getType, groupingBy(dish -> {
    4. if (dish.getCalories() <= 400)
    5. return CaloricLevel.DIET;
    6. else if (dish.getCalories() <= 700)
    7. return CaloricLevel.NORMAL;
    8. else
    9. return CaloricLevel.FAT;
    10. })
    11. ));

     很好理解,就是嵌套使用,不做过多解释。

    先分组,在组内做统计

    1. 先分组,再统计个数

    1. Map typesCount = menu.stream()
    2. .collect(groupingBy(Dish::getType, counting()));

    groupBy()有两个入参,第一个是分组条件,第二个是统计操作,这里是counting()进行计数。

    2. 先分组,再取最大值

    1. Map> mostCaloricByType = menu.stream()
    2. .collect(groupingBy(Dish::getType, maxBy(comparingInt(Dish::getCalories))));

    这里是maxBy()求算最大值。

    3. 由于取最大值可能不存在,我们可以使用collectingAndThen方法,进行后续取值操作Optional::get

    1. Map mostCaloricByType = menu.stream()
    2. .collect(groupingBy(Dish::getType,
    3. collectingAndThen(maxBy(comparingInt(Dish::getCalories)),
    4. Optional::get)));

    4. 先分组,再求和

    1. Map totalCaloriesByType =
    2. menu.stream().collect(groupingBy(Dish::getType,
    3. summingInt(Dish::getCalories)));

    先按照type进行分组,内部使用summingInt求和计算。

    5. 先分组,再映射

    1. Map> result = menu.stream()
    2. .collect(groupingBy(Dish::getType,
    3. mapping(dish -> {
    4. if (dish.getCalories() <= 400)
    5. return CaloricLevel.DIET;
    6. else if (dish.getCalories() <= 700)
    7. return CaloricLevel.NORMAL;
    8. else
    9. return CaloricLevel.FAT;
    10. }, toSet())));

    这里进行了几层嵌套:

    collect

            groupingBy

                            mapping

                                            rule, toSet

    最后的toSet是没法保证是用什么实现的,HashSet还是其他,我们可以使用toCollection(HashSet::new)指定

    1. Map> result = menu.stream()
    2. .collect(groupingBy(Dish::getType,
    3. mapping(dish -> {
    4. if (dish.getCalories() <= 400)
    5. return CaloricLevel.DIET;
    6. else if (dish.getCalories() <= 700)
    7. return CaloricLevel.NORMAL;
    8. else
    9. return CaloricLevel.FAT;
    10. }, toCollection(HashSet::new)
    11. )));

  • 相关阅读:
    使用高德开放平台显示指定的坐标点和线
    springboot简述
    ​市场翘首以待本周三美国的通胀报告 美元指数先跌为敬
    实施运维03(在虚拟机上安装winServer2008系统)
    flutter在导航栏处实现对两个列表的点击事件
    【PHP进阶】Rabbitmq的实际使用
    MyBatis中的ResultMap有什么作用
    VS2019编译安装GDAL(C++)程序库
    maven中 depedencyManagement的作用
    清华大学ucore操作系统课笔记
  • 原文地址:https://blog.csdn.net/Day_and_Night_2017/article/details/125902314