Java8 stream 中利用 groupingBy 进行多字段分组求和

Java8 stream 中利用 groupingBy 进行多字段分组求和Java8的groupingBy实现集合的分组,类似Mysql的groupby分组功能,注意得到的是一个map对集合按照单个属性分组、分组计数、排序List<String>items=Arrays.asList(“apple”,”apple”,”banana”,”apple”,”orange”,”ba…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

Java8的groupingBy实现集合的分组,类似Mysql的group by分组功能,注意得到的是一个map

 

对集合按照单个属性分组、分组计数、排序

List<String> items =
        Arrays.asList("apple", "apple", "banana",
                "apple", "orange", "banana", "papaya");

// 分组
Map<String, List<String>> result1 = items.stream().collect(
        Collectors.groupingBy(
                Function.identity()
        )
);
//{papaya=[papaya], orange=[orange], banana=[banana, banana], apple=[apple, apple, apple]}
System.out.println(result1);


// 分组计数
Map<String, Long> result2 = items.stream().collect(
        Collectors.groupingBy(
                Function.identity(), Collectors.counting()
        )
);
// {papaya=1, orange=1, banana=2, apple=3}
System.out.println(result2);
Map<String, Long> finalMap = new LinkedHashMap<>();


//分组, 计数和排序
result2.entrySet().stream()
        .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
        .forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
// {apple=3, banana=2, papaya=1, orange=1}
System.out.println(finalMap);

 

集合按照多个属性分组

1.多个属性拼接出一个组合属性

public static void main(String[] args) {
    User user1 = new User("zhangsan", "beijing", 10);
    User user2 = new User("zhangsan", "beijing", 20);
    User user3 = new User("lisi", "shanghai", 30);
    List<User> list = new ArrayList<User>();
    list.add(user1);
    list.add(user2);
    list.add(user3);
    Map<String, List<User>> 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);
}


private static String fetchGroupKey(User user){
    return user.getName() +"#"+ user.getAddress();
}

2.嵌套调用groupBy

User user1 = new User("zhangsan", "beijing", 10);
User user2 = new User("zhangsan", "beijing", 20);
User user3 = new User("lisi", "shanghai", 30);
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
Map<String, Map<String, List<User>>> 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') as window, --round timestamp to the nearest 5 minute
  cdn, 
  isp, 
  http_result_code, 
  transaction_time, 
  sum(bytes_transferred)
from web_records
group by 
    round(request_timestamp, '5'), 
    cdn, 
    isp, 
    http_result_code, 
    transaction_time

在java 8中,我当前的第一次尝试是这样的,我知道这个解决方案类似于Group by multiple field names in java 8

Map<Date, Map<String, Map<String, Map<String, Map<String, Integer>>>>>>> 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 (Date window : aggregatedData.keySet()) {
  for (String cdn : aggregatedData.get(window).keySet()) {
    for (String isp : aggregatedData.get(window).get(cdn).keySet()) {
      for (String resultCode : aggregatedData.get(window).get(cdn).get(isp).keySet()) {
        for (String txnTime : aggregatedData.get(window).get(cdn).get(isp).get(resultCode).keySet()) {

           Integer bytesTransferred = aggregatedData.get(window).get(cdn).get(distId).get(isp).get(resultCode).get(txnTime);
           AggregatedRow row = new AggregatedRow(window, cdn, distId...

如你所见,这是相当混乱和难以维持。
有谁知道更好的方法吗?任何帮助都将不胜感激。
我想知道是否有更好的方法来展开嵌套的映射,或者是否有一个库允许您对集合进行分组。

 

最佳答案

您应该为地图创建自定义密钥。最简单的方法是使用Arrays.asList

Function<WebRecord, List<Object>> keyExtractor = wr ->
    Arrays.<Object>asList(wr.getFiveMinuteWindow(), wr.getCdn(), wr.getIsp(),
             wr.getResultCode(), wr.getTxnTime());

Map<List<Object>, Integer> aggregatedData = webRecords.stream().collect(
      Collectors.groupingBy(keyExtractor, Collectors.summingInt(WebRecord::getReqBytes)));

在这种情况下,键是按固定顺序列出的5个元素。不是很面向对象,但很简单。或者,您可以定义自己的表示自定义键的类型,并创建适当的hashCode/equals实现。

参考链接:

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/171278.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 西门子scl语言编程教程_西门子scl编程

    西门子scl语言编程教程_西门子scl编程《在西门子PLC中使用SCL语言编程的技巧》由会员分享,可在线阅读,更多相关《在西门子PLC中使用SCL语言编程的技巧(6页珍藏版)》请在人人文库网上搜索。1、在西门子PLC中使用SCL语言编程的技巧前言:两年半前我就在工控网上发表了有关SCL编程的知识#lt;#lt;在S型PLC中使用高级语言编程#gt;#gt;,但发表完后,即使我自己都从没有把任何使用SCL编写的程序用到实际控制中,当时的感觉…

    2022年10月7日
    0
  • activity的用法总结_pagemanager

    activity的用法总结_pagemanagerActivityManager总结列表1.公共方法(1)getMemoryClass()通过以兆为单位获取当前应用可用的内存大小。(2)getLargeMemoryClass()当开发者在manifest文件中的标签中设置largeHeap属性的值为”true”时,当前应用就可以获取到系统分配的最大堆内存.如果你设置了该值,可以通过ActivityMa

    2022年9月6日
    2
  • RFC2616-HTTP1.1-Status Code(状态码规定部分—译文)

    partof HypertextTransferProtocol–HTTP/1.110状态码规定(StatusCodeDefinitions)本文描述了每一个状态码的相

    2022年3月25日
    42
  • 华为 eNSP 模拟器安装教程(内含下载地址)[通俗易懂]

    华为 eNSP 模拟器安装教程(内含下载地址)[通俗易懂]本文指导大家在Windows操作系统上完成华为eNSP模拟器的安装

    2022年10月9日
    0
  • MyEclipse SVN插件的安装详解[通俗易懂]

    MyEclipse SVN插件的安装详解[通俗易懂]一、安装类型(一)、在线安装1.打开Myeclipse,在菜单栏中选择Help→SoftwareUpdates→FindandInstall;2.选择Searchfornewfeaturestoinstall,点击Next进入下一步;

    2022年7月20日
    10
  • Centos7下安装Docker(详细安装教程)[通俗易懂]

    一,Docker简介百科说:Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。看起来有点雾,用过虚拟机的应该对虚拟化技术有点印象,不知道也没关系,就把它当成轻量级的虚拟机吧(虽然一个是完全虚拟化,一个是操作系统层虚拟化),这个解释到位:ht…

    2022年4月10日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号