Java中基于姓名属性匹配,按对应数量移除列表元素
问题解决:高效移除List中匹配姓名的首个元素
原代码问题分析
你的代码存在两个核心问题:
- 过滤条件错误:
person.firstName = p.firstName是赋值操作,不是字符串比较,正确写法应为person.firstName.equals(p.firstName) - 效率与并发问题:每次遍历people2都对people1做全量线性扫描,时间复杂度为O(n*m);同时直接在Stream操作中调用
people1.remove(person)会触发ConcurrentModificationException(ArrayList迭代器为快速失败机制)
高效实现方案
方案1:基于姓名频率统计+构建新列表(最优,时间复杂度O(n+m))
先统计people2中每个姓名的出现次数,再遍历people1,仅保留超出对应姓名移除次数的元素:
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Person { private String firstName; private Integer age; public Person(String firstName, Integer age) { this.firstName = firstName; this.age = age; } // 重写toString方便打印结果 @Override public String toString() { return firstName + ", " + age; } public String getFirstName() { return firstName; } } public class Main { public static void main(String[] args) { Person p1 = new Person("John", 25); Person p2 = new Person("Lisa", 54); Person p3 = new Person("Mike", 61); Person p4 = new Person("John", 61); Person p5 = new Person("John", 13); List<Person> people1 = new ArrayList<>(); people1.add(p1); people1.add(p2); people1.add(p3); people1.add(p4); people1.add(p5); Person p6 = new Person("John", 88); Person p7 = new Person("Lisa", 66); Person p8 = new Person("Mike", 71); List<Person> people2 = new ArrayList<>(); people2.add(p6); people2.add(p7); people2.add(p8); // 统计people2中每个姓名需要移除的次数 Map<String, Long> nameRemoveCount = people2.stream() .map(Person::getFirstName) .collect(Collectors.groupingBy(name -> name, Collectors.counting())); List<Person> result = new ArrayList<>(); for (Person person : people1) { String name = person.getFirstName(); // 如果该姓名还有需要移除的次数,跳过当前元素(即移除),否则加入结果列表 if (nameRemoveCount.containsKey(name) && nameRemoveCount.get(name) > 0) { nameRemoveCount.put(name, nameRemoveCount.get(name) - 1); } else { result.add(person); } } // 替换原列表(如需保留原列表引用) people1.clear(); people1.addAll(result); System.out.println(people1); // 输出: [John, 61, John, 13] } }
方案2:迭代器遍历移除(适合小列表,时间复杂度O(n*m))
如果列表规模不大,可直接用迭代器遍历people1,找到首个匹配姓名的元素并移除:
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Main { public static void main(String[] args) { // 初始化代码同方案1... for (Person p : people2) { Iterator<Person> iterator = people1.iterator(); while (iterator.hasNext()) { Person person = iterator.next(); if (person.getFirstName().equals(p.getFirstName())) { iterator.remove(); // 用迭代器移除,避免并发修改异常 break; // 仅移除第一个匹配项,跳出循环 } } } System.out.println(people1); // 输出: [John, 61, John, 13] } }
方案对比
- 方案1:时间复杂度O(n+m),通过一次统计+一次遍历完成,效率最高,适合大列表场景
- 方案2:时间复杂度O(n*m),实现简单直观,适合数据量较小的场景
内容的提问来源于stack exchange,提问作者Sherbet Head
相关产品推荐
相关产品推荐

