如何用Java Stream实现基于索引分组的嵌套值计数Map?
问题描述
给定List<Integer> l和整数因子f,需要用Stream创建Map<Integer, Map<Integer, Long>> m:外层Map的键是列表索引除以f的结果,内层Map是对应分组中各值的出现次数。
示例
当列表为{1,1,1,4}、f=2时,结果为:
0 -> { 1 -> 2 } 1 -> { 1 -> 1 4 -> 1 }
已有循环实现
Map<Integer, Map<Integer, Long>> m = new HashMap<>(); for (int i = 0; i < l.size(); i++) { m.computeIfAbsent(i/f, k -> new HashMap<>()) .compute(l.get(i), (k, v) -> v==null?1:v+1); }
已知基础写法
已经掌握用Stream做简单分组计数的写法:
Map<Integer, Long> m = l.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
现在的困惑是不知道如何结合索引分组完成嵌套统计,考虑用IntStream.range获取索引,但不清楚正确的计数收集方式。
解决方案
可以通过IntStream.range遍历索引,将索引与元素配对后,用嵌套的groupingBy完成双层分组统计,代码如下:
import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; public class StreamGroupingDemo { public static void main(String[] args) { List<Integer> l = List.of(1, 1, 1, 4); int f = 2; Map<Integer, Map<Integer, Long>> result = IntStream.range(0, l.size()) // 将索引和对应元素打包成数组,保留两者关联关系 .mapToObj(i -> new int[]{i, l.get(i)}) // 外层分组:按索引除以f的结果作为键 .collect(Collectors.groupingBy( arr -> arr[0] / f, // 内层分组:对每个子组的元素统计出现次数 Collectors.groupingBy( arr -> arr[1], Collectors.counting() ) )); // 打印验证结果 result.forEach((outerKey, innerMap) -> { System.out.println(outerKey + " -> "); innerMap.forEach((value, count) -> System.out.println(" " + value + " -> " + count)); }); } }
代码逻辑说明
- 生成索引流:
IntStream.range(0, l.size())生成覆盖所有列表元素索引的流,确保每个元素的位置信息都能被获取。 - 关联索引与元素:用
mapToObj把索引和对应元素包装成数组,这样在流处理中能同时操作索引和元素值。 - 外层分组:以
arr[0]/f作为分组键,对应外层Map的键,实现按索引分段的需求。 - 内层计数:每个外层分组内,再以元素值为键,用
Collectors.counting()统计该值在当前分段中的出现次数,生成内层的计数Map。
这个实现和循环版本的逻辑完全一致,用Stream API完成了嵌套分组统计的需求。
内容的提问来源于stack exchange,提问作者EdmCoff
相关产品推荐
相关产品推荐

