如何使用Java Stream按列表内多元素分组嵌套列表?
问题描述
我有以下嵌套列表数据:
List<ArrayList<String>> dummy = new ArrayList<>(); dummy.add(new ArrayList<>(List.of("1", "SP1", "SW1"))); dummy.add(new ArrayList<>(List.of("2", "SP1", "SW2"))); dummy.add(new ArrayList<>(List.of("3", "SP2", "SW1"))); dummy.add(new ArrayList<>(List.of("4", "SP2", "SW2"))); dummy.add(new ArrayList<>(List.of("5", "SP2", "SW1"))); dummy.add(new ArrayList<>(List.of("6", "SP1", "SW1"))); dummy.add(new ArrayList<>(List.of("7", "SP3", "SW2")));
期望得到的分组结果是:
SW1-SP1-list{1,6} SW1-SP2-list{3,5} SW2-SP1-list{2} SW2-SP2-list{4} SW2-SP3-list{7}
我尝试了这段代码,但无法得到预期结果:
var test = dummy.stream() .collect(Collectors.groupingBy( s -> s.get(2), TreeMap::new, Collectors.groupingBy( s -> s.get(1), Collectors.toList() ) ));
请问如何实现正确的分组?
解决方案
你的代码问题在于最后收集的是整个子列表,而不是只提取每个子列表中的第一个元素(即编号)。另外要得到和预期一致的输出格式,还需要对分组后的结果做遍历格式化。
正确的分组与输出代码
// 完成分组,仅收集每个条目里的编号 var grouped = dummy.stream() .collect(Collectors.groupingBy( s -> s.get(2), // 外层按SW值分组 TreeMap::new, // 用TreeMap保证SW的有序性 Collectors.groupingBy( s -> s.get(1), // 内层按SP值分组 Collectors.mapping( s -> s.get(0), // 提取每个子列表的编号(索引0的元素) Collectors.toList() ) ) )); // 按预期格式输出结果 grouped.forEach((sw, spMap) -> { spMap.forEach((sp, ids) -> { System.out.printf("%s-%s-list{%s}%n", sw, sp, String.join(",", ids)); }); });
代码说明
Collectors.mapping:替换原代码中的Collectors.toList(),专门用来将每个子列表转换为仅保留编号,这样每个SP分组下存储的就是需要的编号列表,而非完整子列表。TreeMap::new:确保外层的SW分组是有序的(比如SW1在前、SW2在后),和预期结果的顺序匹配。- 遍历格式化:通过两层
forEach遍历SW和SP的映射关系,用printf拼接成预期的字符串格式输出。
运行上述代码后,会输出完全符合要求的结果:
SW1-SP1-list{1,6} SW1-SP2-list{3,5} SW2-SP1-list{2} SW2-SP2-list{4} SW2-SP3-list{7}
内容的提问来源于stack exchange,提问作者xfactor
相关产品推荐
相关产品推荐

