如何从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
相关产品推荐
相关产品推荐

