Java Stream实现多级分组、多聚合、排序及结果格式问题咨询
问题排查与正确实现方案
现有代码的核心问题
- 测试数据构造存在遗漏:构造完
name=pqr, price=500的Map对象后,没有执行lm.add(ms)将其加入原始数据集,导致该条数据未参与分组计算,最终pqr组的聚合值和预期不符。 - 分组逻辑结构偏差:使用两层嵌套
groupingBy生成的是嵌套Map结构,没有将分组字段(name、color)扁平化到每一条结果记录中,无法直接得到目标格式的List<Map<String, Object>>。 - 聚合值存储方式不合理:使用
AbstractMap.SimpleEntry存储聚合结果,无法将price平均值、days求和值拆分为独立的Map字段,最终输出是嵌套的键值对字符串。
正确实现代码
1. 先修正测试数据遗漏
在构造完price=500的pqr对应Map后补上add操作:
// 补上这行,把漏掉的pqr数据加入列表 lm.add(ms);
2. 聚合与分组核心逻辑
import java.util.*; import java.util.stream.Collectors; public class StreamAggDemo { public static void main(String[] args) { // 你的原始测试数据(已补上漏add的那条pqr记录) List<Map<String, Object>> lm = new ArrayList<>(); // ... 之前的所有put和add逻辑,补上遗漏的lm.add(对应500price的ms对象) // 1. 用复合键(name+color)做分组,避免嵌套Map Map<Map.Entry<String, String>, List<Map<String, Object>>> groupedMap = lm.stream() .collect(Collectors.groupingBy(item -> new AbstractMap.SimpleEntry<>( item.get("name").toString(), item.get("color").toString() ) )); // 2. 将每个分组转换为扁平化的结果行 List<Map<String, Object>> result = groupedMap.entrySet().stream() .map(entry -> { String groupName = entry.getKey().getKey(); String groupColor = entry.getKey().getValue(); List<Map<String, Object>> currentGroup = entry.getValue(); // 计算同组price平均值 double avgPrice = currentGroup.stream() .mapToInt(item -> (int) item.get("price")) .average() .orElse(0.0); // 计算同组days求和 int sumDays = currentGroup.stream() .mapToInt(item -> (int) item.get("days")) .sum(); // 组装目标结构 Map<String, Object> row = new HashMap<>(); row.put("name", groupName); row.put("color", groupColor); row.put("price", avgPrice); row.put("days", sumDays); return row; }) // 3. 排序逻辑可按需替换:这里示例为按days字段降序 .sorted(Comparator.comparingInt(row -> (int) row.get("days")).reversed()) .collect(Collectors.toList()); // 输出验证 System.out.println(result); } }
排序逻辑说明
只要替换sorted()方法里的Comparator实现,即可按任意指定字段排序:
- 按price升序:
Comparator.comparingDouble(row -> (double) row.get("price")) - 按name字典序升序:
Comparator.comparing(row -> (String) row.get("name")) - 多字段组合排序:比如先按days降序,再按price升序:
.sorted(Comparator.comparingInt((Map<String, Object> row) -> (int) row.get("days")).reversed() .thenComparingDouble(row -> (double) row.get("price")))
最终输出效果
修正后运行结果将完全匹配预期格式,输出顺序由设置的排序规则决定,示例为按days降序的结果:
[ {"name":"xyz", "color":"orange", "price":5000.0, "days":30}, {"name":"pqr", "color":"blue", "price":1500.0, "days":7}, {"name":"abc", "color":"red", "price":3000.0, "days":3} ]
内容的提问来源于stack exchange,提问作者user3458271
相关产品推荐
相关产品推荐

