使用Stream收集数据

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

collect 是一个归约操作,就像 reduce 一样可以接受各种做法作为参数,将流中的元素累积成一个汇总结果。具体的做法是通过定义新的Collector 接口来定义的。

一、使用方法

1.规约和汇总

public static void collectTest(){
        List<Integer> numbers = Arrays.asList(1,2,3,4,5);
        System.out.println(numbers.stream().count());//元素个数
        Map<Boolean, List<Integer>> collect = numbers.stream().collect(groupingBy(i -> i % 2 == 0));//以奇偶数分组
        System.out.println(collect.get(true));
        System.out.println(numbers.stream().collect(maxBy(Comparator.comparingInt(i->i))));//最大值
        System.out.println(numbers.stream().collect(summingInt(i->i)));//和
        System.out.println(numbers.stream().collect(summarizingInt(i->i)));//一劳永逸,常用汇总数据
        System.out.println(numbers.stream().map(i->i+"").collect(joining(",")));//连接字符串,并设置分隔符
    }
5
[2, 4]
Optional[5]
15
IntSummaryStatistics{count=5, sum=15, min=1, average=3.000000, max=5}
1,2,3,4,5

2.分组

  1. 单级分组

按照一个属性对集合中的项目进行分组

实战:按照Dish的type进行分组

public class Dish {
    String type;
    String name;
    int costs;
}
public static void groupTest() {
        List<Dish> dishes=Arrays.asList(new Dish("fish","prawns",200),
                new Dish("fish","salmon",200),
                new Dish("meat","pock",20),
                new Dish("meat","beef",30),
                new Dish("meat","chicken",400),
                new Dish("other","rice",50),
                new Dish("other","fruit",60),
                new Dish("other","pizza",700));//数据数组
        Map<String,List<Dish>> dishByType=
                dishes.stream().collect(Collectors.groupingBy(Dish::getType));//按照分类分组
        for(Map.Entry type : dishByType.entrySet()){
            String key=type.getKey().toString();
            System.out.print(key+":");
            List<Dish> dishes1=(List)type.getValue();
            dishes1.forEach(o-> System.out.print(o.getName()+" "));
            System.out.println();
        }//遍历输出
    }

输出结果

other:rice fruit pizza 
fish:prawns salmon 
meat:pock beef chicken
  1. 多级分组

按照多个属性对集合中的项目进行分组,在分组的基础上再进行分组。

实战:在按照type进行分组的基础上再按照花费进行分组

public enum Level { EXPENSIVE, NORMAL}//枚举来表示分级

Map<String,Map<Level,List<Dish> > > dishesByMuti=
                dishes.stream().collect(Collectors.groupingBy(Dish::getType,//一级分组
                        Collectors.groupingBy(o ->{//二级分组
                            if(o.getCosts()>100) return Level.EXPENSIVE;
                            else return Level.NORMAL;
                        })));
        for(Map.Entry type : dishesByMuti.entrySet()){//遍历
            String key=type.getKey().toString();
            System.out.print(key+": [");
            Map<Level,List<Dish>> typeList=(Map)type.getValue();
            for(Map.Entry level : typeList.entrySet()){
                String levelName=level.getKey().toString();
                List<Dish> list=(List) level.getValue();
                System.out.print(levelName+"[");
                list.forEach(o->{
                    System.out.print(o.getName()+":"+o.getCosts()+",");
                });
                System.out.print("]");
            }
            System.out.println(" ]");
        }

输出结果

other: [ EXPENSIVE[pizza:700,]NORMAL[rice:50,fruit:60,] ]
fish: [ EXPENSIVE[prawns:200,salmon:200,] ]
meat: [ EXPENSIVE[chicken:400,]NORMAL[pock:20,beef:30,] ]

3.分区

分区是分组的特殊情况:由一个谓词(返回一个布尔值的函数)作为分类函数,它称分区函数。分区函数返回一个布尔值,这意味着得到的分组 Map 的键类型是 Boolean,于是它最多可以分为两组——true 是一组,false 是一组。

实战:按照菜品是否便宜分组

public static Boolean isCheap(Dish dish){
        return dish.getCosts()<50;
}
Map<Boolean,List<Dish>> cheapMap=
                dishes.stream().collect(Collectors.partitioningBy(Dish::isCheap));
        for(Map.Entry type : cheapMap.entrySet()){
            String key=type.getKey().toString();
            System.out.print(key+":[ ");
            List<Dish> dishes1=(List)type.getValue();
            dishes1.forEach(o-> System.out.print(o.getName()+":"+o.getCosts()+","));
            System.out.println(" ]");
        }

输出结果

false:[ prawns:200,salmon:200,chicken:400,rice:50,fruit:60,pizza:700, ]
true:[ pock:20,beef:30, ]

其实也可以通过filter进行两次查询

//便宜的集合,不便宜的类似
 Map<Boolean,List<Dish>> cheapMap=
                dishes.stream().collect(Collectors.partitioningBy(Dish::isCheap));
        List<Dish> cheapMap2=
                dishes.stream().filter(Dish::isCheap).collect(toList());
        cheapMap2.forEach(o->{
            System.out.print(o.getName()+",");
        });
pock
beef

其实分区和删选都能完成改需求,但分区的好处在于保留了分区函数返回 true 或 false 的两套流元素列表。

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

上一篇:Luogu 2911


下一篇:Java8 stream流之分组 groupingBy 的使用