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<String, Object>>,从下图可看出
其中分组李四有两条数据,张三有五条, 王五有三条
在这里插入图片描述
后面我们将分组后的map:mapListGroupByName进行聚合操作:求和、平均值、最大值、最小值和BigDecimal求和形成一个新的 List<Map<String, Object>>对象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);
}
————————————————
版权声明:本文为CSDN博主「小诺大人」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ayunnuo/article/details/125232239