网络知识 娱乐 Java stream对List对象进行分组聚合操作:求和、平均值、最大值、最小值,BigDecimal求和

Java stream对List对象进行分组聚合操作:求和、平均值、最大值、最小值,BigDecimal求和

代码

package com.kabka.test;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * List 分组求和
 *
 * @author yunnuo
 * @since 2022-06-11
 */
@Slf4j
public class ListGroupSumTest {

    @Test
    public void testSum() {
        List<Map<String, Object>> mapList = new ArrayList<>();

        String[] names = {"张三", "李四", "王五"};

        // 循环mock 随机值
        for (int i = 0; i < 10; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", names[new Random().nextInt(3)]);
            map.put("value", i);
            map.put("money", new BigDecimal(new Random().nextFloat() * i).setScale(4, BigDecimal.ROUND_DOWN));
            mapList.add(map);
        }
        log.info("原始未分组mapList:{}", JSONUtil.toJsonStr(mapList));
        // 通过name进行分组
        Map<String, List<Map<String, Object>>> mapListGroupByName = mapList.stream().collect(Collectors.groupingBy(map -> map.get("name").toString()));
        log.info("分组后:{}", JSONUtil.toJsonStr(mapListGroupByName));

        List<Map<String, Object>> groupMapList = new ArrayList<>();
        // 对分组数据进行求和操作
        mapListGroupByName.forEach((name, mapByNameList) -> {
            HashMap<String, Object> reMap = new HashMap<>();
            // 求和
            int sum = mapByNameList.stream().mapToInt(map -> Integer.parseInt(map.get("value").toString())).sum();
            // 最大值
            OptionalInt maxOpt = mapByNameList.stream().mapToInt(map -> Integer.parseInt(map.get("value").toString())).max();
            // 最小值
            Long count = mapByNameList.stream().mapToInt(map -> Integer.parseInt(map.get("value").toString())).count();
            // 平均值
            OptionalDouble averageOpt = mapByNameList.stream().mapToInt(map -> Integer.parseInt(map.get("value").toString())).average();

            BigDecimal sumMoney = new BigDecimal(0);
            // BigDecimal 进行 求和
            for (Map<String, Object> map : mapByNameList) {
                BigDecimal money = new BigDecimal(map.get("money").toString());
                sumMoney= sumMoney.add(money);
            }

            reMap.put("name", name);
            reMap.put("sum", sum);
            reMap.put("count", count);
            reMap.put("sumMoney", sumMoney);
            maxOpt.ifPresent(max -> reMap.put("max", max));
            averageOpt.ifPresent(average -> reMap.put("average", average));
            groupMapList.add(reMap);
        });
        log.info("分组后聚合List:{}", JSONUtil.toJsonStr(groupMapList));
    }
}

解析

本博主采用map来代替DTO,进行对map对象->mapList循环随机赋值,属性分别为:name、value、money
在这里插入图片描述
然后对mapList 通过name属性进行分组 生成新的map为 mapListGroupByName,其中生成的map的key是采用分组的name作为key,相同name的map则放在一起生成mapListGroupByName的value值 :List<Map>,从下图可看出
其中分组李四有两条数据,张三有五条, 王五有三条
在这里插入图片描述

后面我们将分组后的map:mapListGroupByName进行聚合操作:求和、平均值、最大值、最小值和BigDecimal求和形成一个新的 List<Map>对象groupMapList,如下图所示
在这里插入图片描述
其中Java8新特性中的stream操作可以对数据进行直接求和、平均值、最大值、最小值等,感兴趣的小伙伴可以自行看api,博主这边还对BigDecimal类型的数据进行求和了,所以一般涉及到金钱等重要数据采用BigDecimal来存储的话,也可以像博主一样进行循环求和操作。

// 求和
int sum = mapByNameList.stream().mapToInt(map -> Integer.parseInt(map.get("value").toString())).sum();
// 最大值
OptionalInt maxOpt = mapByNameList.stream().mapToInt(map -> Integer.parseInt(map.get("value").toString())).max();
// 最小值
Long count = mapByNameList.stream().mapToInt(map -> Integer.parseInt(map.get("value").toString())).count();
// 平均值
OptionalDouble averageOpt = mapByNameList.stream().mapToInt(map -> Integer.parseInt(map.get("value").toString())).average();

BigDecimal sumMoney = new BigDecimal(0);
// BigDecimal 进行 求和
for (Map<String, Object> map : mapByNameList) {
    BigDecimal money = new BigDecimal(map.get("money").toString());
    sumMoney= sumMoney.add(money);
}