Java8 stream 中利用 groupingBy 进行多字段分组求和案例
Java8的groupingBy实现集合的分组,类似Mysql的groupby分组功能,注意得到的是一个map
对集合按照单个属性分组、分组计数、排序
Listitems= Arrays.asList("apple","apple","banana", "apple","orange","banana","papaya"); //分组 Map >result1=items.stream().collect( Collectors.groupingBy( Function.identity() ) ); //{papaya=[papaya],orange=[orange],banana=[banana,banana],apple=[apple,apple,apple]} System.out.println(result1); //分组计数 Map result2=items.stream().collect( Collectors.groupingBy( Function.identity(),Collectors.counting() ) ); //{papaya=1,orange=1,banana=2,apple=3} System.out.println(result2); Map finalMap=newLinkedHashMap<>(); //分组,计数和排序 result2.entrySet().stream() .sorted(Map.Entry. comparingByValue().reversed()) .forEachOrdered(e->finalMap.put(e.getKey(),e.getValue())); //{apple=3,banana=2,papaya=1,orange=1} System.out.println(finalMap);
集合按照多个属性分组
1.多个属性拼接出一个组合属性
publicstaticvoidmain(String[]args){ Useruser1=newUser("zhangsan","beijing",10); Useruser2=newUser("zhangsan","beijing",20); Useruser3=newUser("lisi","shanghai",30); Listlist=newArrayList (); list.add(user1); list.add(user2); list.add(user3); Map >collect=list.stream().collect(Collectors.groupingBy(e->fetchGroupKey(e))); //{zhangsan#beijing=[User{age=10,name='zhangsan',address='beijing'},User{age=20,name='zhangsan',address='beijing'}], //lisi#shanghai=[User{age=30,name='lisi',address='shanghai'}]} System.out.println(collect); } privatestaticStringfetchGroupKey(Useruser){ returnuser.getName()+"#"+user.getAddress(); }
2.嵌套调用groupBy
Useruser1=newUser("zhangsan","beijing",10); Useruser2=newUser("zhangsan","beijing",20); Useruser3=newUser("lisi","shanghai",30); Listlist=newArrayList (); list.add(user1); list.add(user2); list.add(user3); Map >>collect =list.stream().collect( Collectors.groupingBy( User::getAddress,Collectors.groupingBy(User::getName) ) ); System.out.println(collect);
3.使用Arrays.asList
我有一个与Web访问记录相关的域对象列表。这些域对象可以扩展到数千个。
我没有资源或需求将它们以原始格式存储在数据库中,因此我希望预先计算聚合并将聚合的数据放在数据库中。
我需要聚合在5分钟窗口中传输的总字节数,如下面的sql查询
select round(request_timestamp,'5')aswindow,--roundtimestamptothenearest5minute cdn, isp, http_result_code, transaction_time, sum(bytes_transferred) fromweb_records groupby round(request_timestamp,'5'), cdn, isp, http_result_code, transaction_time
在java8中,我当前的第一次尝试是这样的,我知道这个解决方案类似于Groupbymultiplefieldnamesinjava8
Map>>>>>>aggregatedData= webRecords .stream() .collect(Collectors.groupingBy(WebRecord::getFiveMinuteWindow, Collectors.groupingBy(WebRecord::getCdn, Collectors.groupingBy(WebRecord::getIsp, Collectors.groupingBy(WebRecord::getResultCode, Collectors.groupingBy(WebRecord::getTxnTime, Collectors.reducing(0, WebRecord::getReqBytes(), Integer::sum)))))));
这是可行的,但它是丑陋的,所有这些嵌套的地图是一个噩梦!要将地图“展平”或“展开”成行,我必须这样做
for(Datewindow:aggregatedData.keySet()){ for(Stringcdn:aggregatedData.get(window).keySet()){ for(Stringisp:aggregatedData.get(window).get(cdn).keySet()){ for(StringresultCode:aggregatedData.get(window).get(cdn).get(isp).keySet()){ for(StringtxnTime:aggregatedData.get(window).get(cdn).get(isp).get(resultCode).keySet()){ IntegerbytesTransferred=aggregatedData.get(window).get(cdn).get(distId).get(isp).get(resultCode).get(txnTime); AggregatedRowrow=newAggregatedRow(window,cdn,distId...
如你所见,这是相当混乱和难以维持。
有谁知道更好的方法吗?任何帮助都将不胜感激。
我想知道是否有更好的方法来展开嵌套的映射,或者是否有一个库允许您对集合进行分组。
最佳答案
您应该为地图创建自定义密钥。最简单的方法是使用Arrays.asList:
Function>keyExtractor=wr-> Arrays.
在这种情况下,键是按固定顺序列出的5个元素。不是很面向对象,但很简单。或者,您可以定义自己的表示自定义键的类型,并创建适当的hashCode/equals实现。
补充知识:java8新特性Stream流分组排序过滤多条件去重(最小、最大、平均、求和)
什么是Stream?
Stream是用函数式编程方式在集合类上进行复杂操作的工具,其集成了Java8中的众多新特性之一的聚合操作,开发者可以更容易地使用Lambda表达式,并且更方便地实现对集合的查找、遍历、过滤以及常见计算等。话不多说,直接上代码。
Listlist=newArrayList (); list=Arrays.asList( newUser("小强",11,"男"), newUser("小玲",15,"女"), newUser("小虎",23,"男"), newUser("小雨",26,"女"), newUser("小飞",19,"男"), newUser("小玲",15,"女") ); //分组 Map >listMap=list.stream().collect(Collectors.groupingBy(User::getSex)); for(Stringkey:listMap.keySet()){ System.out.print(key+"组:"); listMap.get(key).forEach(user->System.out.print(user.getName())); System.out.println(); } //排序 list.stream().sorted(Comparator.comparing(user->user.getAge())) .forEach(user->System.out.println(user.getName())); //过滤 list.stream().filter(user->user.getSex().equals("男")).collect(Collectors.toList()) .forEach(user->System.out.println(user.getName())); //多条件去重 list.stream().collect(Collectors.collectingAndThen( Collectors.toCollection(()->newTreeSet<>( Comparator.comparing(user->user.getAge()+";"+user.getName()))),ArrayList::new)) .forEach(user->System.out.println(user.getName())); //最小值 Integermin=list.stream().mapToInt(User::getAge).min().getAsInt(); //最大值 Integermax=list.stream().mapToInt(User::getAge).max().getAsInt(); //平均值 Doubleaverage=list.stream().mapToInt(User::getAge).average().getAsDouble(); //和 Integersum=list.stream().mapToInt(User::getAge).sum(); System.out.println("最小值:"+min+",最大值"+max+",平均值:"+average+",和:"+sum); //分组求和 Map collect=list.stream().collect(Collectors.groupingBy(User::getSex,Collectors.summarizingInt(User::getAge))); IntSummaryStatisticsstatistics1=collect.get("男"); IntSummaryStatisticsstatistics2=collect.get("女"); System.out.println(statistics1.getSum()); System.out.println(statistics1.getAverage()); System.out.println(statistics1.getMax()); System.out.println(statistics1.getMin()); System.out.println(statistics1.getCount()); System.out.println(statistics2.getSum()); System.out.println(statistics2.getAverage()); System.out.println(statistics2.getMax()); System.out.println(statistics2.getMin()); System.out.println(statistics2.getCount()); //提取list中两个属性值,转为map Map userMap=list.stream().collect(Collectors.toMap(User::getName,User::getSex)); System.out.println(JsonUtil.toJson(userMap)) //取出所有名字 List names=list.stream().map(User::getName).collect(Collectors.toList()); System.out.println(JsonUtil.toJson(names))
以上这篇Java8stream中利用groupingBy进行多字段分组求和案例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。