You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据不同类型按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();
        }
    }
}

代码说明

  1. Getter方法:Obj类必须添加字段的getter方法,因为Stream的groupingBy需要通过方法引用获取字段值。
  2. 分组逻辑:
    • type_1和type_2直接用字段的方法引用作为分组key;
    • type_3有两种实现方式:字符串拼接简单但存在字段包含分隔符的风险,自定义key类更安全但需要重写equals和hashCode方法。
  3. 结果转换:groupingBy返回Map<K, List<Obj>>,调用values()获取所有分组的列表,再转换为List<List<Obj>>。

内容的提问来源于stack exchange,提问作者Neo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:15:42