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

如何从List<List<MyObject>>中移除子集与重复列表?

移除嵌套列表中的子集与重复子列表解决方案

核心思路

  • 先将每个子列表转换为ID集合:判断子集或重复仅依赖MyObject的id,用Set可高效完成包含性检查。
  • 去重:移除所有ID集合完全相同的重复子列表。
  • 筛选非子集:移除所有被其他子列表的ID集合严格包含的子列表(即存在另一个子列表的ID集合包含当前集合,且两者不相等)。

代码实现

首先确保MyObject类有获取id的方法:

public class MyObject {
    private int id;
    // 构造方法、其他字段/方法...
    public int getId() {
        return id;
    }
}

基础版本(适合小规模数据)

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ListProcessor {

    public static List<List<MyObject>> removeSubsetsAndDuplicates(List<List<MyObject>> originalList) {
        // 1. 将每个子列表转换为ID的HashSet,提升后续判断效率
        List<Set<Integer>> idSets = originalList.stream()
                .map(subList -> subList.stream()
                        .map(MyObject::getId)
                        .collect(Collectors.toCollection(HashSet::new)))
                .collect(Collectors.toList());

        // 2. 去重:保留唯一的子列表(ID集合相同的只留第一个出现的)
        List<List<MyObject>> uniqueLists = new ArrayList<>();
        Set<Set<Integer>> seenSets = new HashSet<>();
        for (int i = 0; i < originalList.size(); i++) {
            Set<Integer> currentSet = idSets.get(i);
            if (seenSets.add(currentSet)) {
                uniqueLists.add(originalList.get(i));
            }
        }

        // 3. 移除所有子集子列表
        List<List<MyObject>> result = new ArrayList<>();
        List<Set<Integer>> uniqueIdSets = uniqueLists.stream()
                .map(subList -> subList.stream()
                        .map(MyObject::getId)
                        .collect(Collectors.toCollection(HashSet::new)))
                .collect(Collectors.toList());

        for (int i = 0; i < uniqueLists.size(); i++) {
            Set<Integer> currentSet = uniqueIdSets.get(i);
            boolean isSubset = false;
            // 检查是否存在其他严格超集
            for (int j = 0; j < uniqueIdSets.size(); j++) {
                if (i == j) continue;
                Set<Integer> otherSet = uniqueIdSets.get(j);
                if (otherSet.containsAll(currentSet) && !otherSet.equals(currentSet)) {
                    isSubset = true;
                    break;
                }
            }
            if (!isSubset) {
                result.add(uniqueLists.get(i));
            }
        }

        return result;
    }
}

优化版本(适合大数据量)

通过按集合大小降序排序,减少子集判断的比较次数:

import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class ListProcessor {

    public static List<List<MyObject>> removeSubsetsAndDuplicates(List<List<MyObject>> originalList) {
        // 1. 转换为ID集合并去重
        List<Set<Integer>> idSets = originalList.stream()
                .map(subList -> subList.stream()
                        .map(MyObject::getId)
                        .collect(Collectors.toCollection(HashSet::new)))
                .collect(Collectors.toList());

        List<List<MyObject>> uniqueLists = new ArrayList<>();
        Set<Set<Integer>> seenSets = new HashSet<>();
        for (int i = 0; i < originalList.size(); i++) {
            Set<Integer> currentSet = idSets.get(i);
            if (seenSets.add(currentSet)) {
                uniqueLists.add(originalList.get(i));
            }
        }

        // 2. 生成子列表与对应ID集合的映射,并按集合大小降序排序
        List<Map.Entry<List<MyObject>, Set<Integer>>> sortedEntries = new ArrayList<>();
        for (int i = 0; i < uniqueLists.size(); i++) {
            Set<Integer> set = uniqueLists.get(i).stream()
                    .map(MyObject::getId)
                    .collect(Collectors.toCollection(HashSet::new));
            sortedEntries.add(new AbstractMap.SimpleEntry<>(uniqueLists.get(i), set));
        }
        sortedEntries.sort((e1, e2) -> Integer.compare(e2.getValue().size(), e1.getValue().size()));

        // 3. 筛选非子集:大集合先加入结果,后续只需要和已加入的大集合比较
        List<List<MyObject>> result = new ArrayList<>();
        for (Map.Entry<List<MyObject>, Set<Integer>> entry : sortedEntries) {
            Set<Integer> currentSet = entry.getValue();
            boolean isSubset = false;
            for (List<MyObject> existing : result) {
                Set<Integer> existingSet = existing.stream().map(MyObject::getId).collect(Collectors.toSet());
                if (existingSet.containsAll(currentSet)) {
                    isSubset = true;
                    break;
                }
            }
            if (!isSubset) {
                result.add(entry.getKey());
            }
        }

        return result;
    }
}

测试示例

public static void main(String[] args) {
    MyObject obj2 = new MyObject();
    obj2.id = 2;
    MyObject obj4 = new MyObject();
    obj4.id = 4;
    MyObject obj10 = new MyObject();
    obj10.id = 10;
    MyObject obj12 = new MyObject();
    obj12.id = 12;

    List<MyObject> list1 = List.of(obj4, obj10, obj12);
    List<MyObject> list2 = List.of(obj4, obj12);
    List<MyObject> list3 = List.of(obj2, obj4, obj12);
    List<MyObject> list4 = List.of(obj4, obj12); // 重复子列表

    List<List<MyObject>> myList = new ArrayList<>();
    myList.add(list1);
    myList.add(list2);
    myList.add(list3);
    myList.add(list4);

    List<List<MyObject>> result = removeSubsetsAndDuplicates(myList);
    // 输出结果:[4, 10, 12]、[2, 4, 12]
    result.forEach(subList -> System.out.println(
            subList.stream().map(MyObject::getId).collect(Collectors.toList())
    ));
}

注意事项

  • 确保MyObject的getId()方法正确返回id字段值。
  • 若子列表的元素顺序不影响重复判断,使用Set处理是高效的;若顺序不同但元素相同不算重复,此方案依然适用。
  • 优化版本适合数据量较大的场景,通过排序减少了不必要的子集判断次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:00:36