如何根据不同类型按Obj的shape/size字段分组List<Obj>?
问题描述
我定义了如下Java类:
public class Obj{ private String size; private String shape; private String name; // 注意:需要添加getter方法,分组时要获取字段值 public String getSize() { return size; } public String getShape() { return shape; } public String getName() { return name; } }
我持有一个Map<String,List<Obj>>,需要根据Map的key值,将对应的List<Obj>按指定字段重新分组,最终得到List<List<Obj>>结构:
- 当key为"type_1"时,按shape字段分组
- 当key为"type_2"时,按size字段分组
- 当key为"type_3"时,按shape和size的组合字段分组
目前已经写出框架代码,但不知道如何实现分组逻辑:
void functionName(Map<String, List<Obj>> objMap){ objMap.forEach((type,objs) -> { switch(type){ case "type_1": // 按shape分组 // 后续处理 break; case "type_2": // 按size分组 // 后续处理 break; case "type_3": // 按shape & size分组 // 后续处理 break; } }); }
输入输出示例
- 示例1:输入Map的key为"type_1",value是包含3个Obj的列表,预期按shape字段分组得到嵌套列表
- 示例2:输入Map的key为"type_3",若所有Obj的shape和size组合都不重复,每个Obj单独成一个子列表
- 示例3:输入Map的key为"type_3",若存在shape和size均相同的Obj,这些Obj会被分到同一个子列表
解决方案
可以利用Java 8及以上的Stream API结合Collectors.groupingBy实现分组逻辑,分组后将Map的values转换为List<List<Obj>>即可。核心是为Obj类添加字段的getter方法,否则无法在分组时获取字段值。
完整实现代码如下:
import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class GroupingExample { public static class Obj{ private String size; private String shape; private String name; // 构造方法(用于创建测试对象) public Obj(String size, String shape, String name) { this.size = size; this.shape = shape; this.name = name; } // 必须添加getter方法 public String getSize() { return size; } public String getShape() { return shape; } public String getName() { return name; } } void functionName(Map<String, List<Obj>> objMap){ objMap.forEach((type, objs) -> { List<List<Obj>> groupedList; switch(type){ case "type_1": // 按shape字段分组 groupedList = objs.stream() .collect(Collectors.groupingBy(Obj::getShape)) .values() .stream() .collect(Collectors.toList()); // 后续处理逻辑可在此添加,比如使用groupedList break; case "type_2": // 按size字段分组 groupedList = objs.stream() .collect(Collectors.groupingBy(Obj::getSize)) .values() .stream() .collect(Collectors.toList()); break; case "type_3": // 方式1:用字符串拼接作为组合key(简单但需注意字段不含分隔符) groupedList = objs.stream() .collect(Collectors.groupingBy(obj -> obj.getShape() + "_" + obj.getSize())) .values() .stream() .collect(Collectors.toList()); // 方式2:用自定义不可变类作为组合key(更安全,避免拼接冲突) // groupedList = objs.stream() // .collect(Collectors.groupingBy(obj -> new ShapeSizeKey(obj.getShape(), obj.getSize()))) // .values() // .stream() // .collect(Collectors.toList()); break; default: groupedList = List.of(); // 处理未知类型逻辑 } // 统一处理分组结果的逻辑可放在此处 }); } // 可选:自定义组合key类(用于type_3的方式2) private static class ShapeSizeKey { private final String shape; private final String size; public ShapeSizeKey(String shape, String size) { this.shape = shape; this.size = size; } // 必须重写equals和hashCode,否则groupingBy无法正确分组 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ShapeSizeKey that = (ShapeSizeKey) o; return shape.equals(that.shape) && size.equals(that.size); } @Override public int hashCode() { return 31 * shape.hashCode() + size.hashCode(); } } }
代码说明
- Getter方法:
Obj类必须添加字段的getter方法,因为Stream的groupingBy需要通过方法引用获取字段值。 - 分组逻辑:
type_1和type_2直接用字段的方法引用作为分组key;type_3有两种实现方式:字符串拼接简单但存在字段包含分隔符的风险,自定义key类更安全但需要重写equals和hashCode方法。
- 结果转换:
groupingBy返回Map<K, List<Obj>>,调用values()获取所有分组的列表,再转换为List<List<Obj>>。
内容的提问来源于stack exchange,提问作者Neo
相关产品推荐
相关产品推荐

