如何从两个含Position对象的ArrayList中提取完全匹配的账户?
筛选符合条件的账户:Java实现方案
前提准备
要判断两个Position对象是否完全匹配,必须重写该类的equals()和hashCode()方法,基于所有属性的值进行比较(默认的对象比较是引用地址比较,无法满足需求):
import java.util.Objects; public class Position { private String account; private String date; private String cycle; private String status; // 构造器 public Position(String account, String date, String cycle, String status) { this.account = account; this.date = date; this.cycle = cycle; this.status = status; } // Getter方法 public String getAccount() { return account; } public String getDate() { return date; } public String getCycle() { return cycle; } public String getStatus() { return status; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Position position = (Position) o; return Objects.equals(account, position.account) && Objects.equals(date, position.date) && Objects.equals(cycle, position.cycle) && Objects.equals(status, position.status); } @Override public int hashCode() { return Objects.hash(account, date, cycle, status); } }
方案一:Java Stream实现(高效简洁)
通过分组+过滤的方式实现,核心思路是:
- 将两个列表按
account分组,得到账户到对应Position集合的映射 - 遍历ListA的分组,检查每个账户是否满足:ListB中存在该账户的分组、两组元素数量一致、ListA的所有Position都在ListB的分组中存在
为了提升匹配效率,可将ListB的分组转为Set(contains操作时间复杂度从O(n)降为O(1)):
import java.util.*; import java.util.stream.Collectors; public class PositionProcessor { public static void main(String[] args) { // 初始化示例数据 List<Position> listA = Arrays.asList( new Position("ACC1", "20-Jan-23", "1", "open"), new Position("ACC1", "20-Jan-23", "2", "closing"), new Position("ACC2", "20-Jan-23", "1", "open"), new Position("ACC2", "20-Jan-23", "2", "closing"), new Position("ACC3", "20-Jan-23", "1", "open"), new Position("ACC3", "20-Jan-23", "2", "closing") ); List<Position> listB = Arrays.asList( new Position("ACC1", "20-Jan-23", "1", "open"), new Position("ACC1", "20-Jan-23", "2", "closing"), new Position("ACC2", "20-Jan-23", "1", "open"), new Position("ACC2", "20-Jan-23", "2", "closed"), new Position("ACC3", "20-Jan-23", "1", "open") ); // 按account分组,ListB转为Set提升匹配效率 Map<String, List<Position>> groupA = listA.stream() .collect(Collectors.groupingBy(Position::getAccount)); Map<String, Set<Position>> groupB = listB.stream() .collect(Collectors.groupingBy(Position::getAccount, Collectors.toSet())); // 筛选符合条件的账户 Set<String> validAccounts = groupA.entrySet().stream() .filter(entry -> { String account = entry.getKey(); List<Position> posA = entry.getValue(); Set<Position> posB = groupB.get(account); return posB != null && posA.size() == posB.size() && posB.containsAll(posA); }) .map(Map.Entry::getKey) .collect(Collectors.toSet()); System.out.println("符合条件的账户:" + validAccounts); // 输出 [ACC1] } }
方案二:标准循环实现(无Stream依赖)
如果项目不支持Java 8+的Stream特性,可以用传统循环分组+匹配:
import java.util.*; public class PositionProcessor { public static void main(String[] args) { // 初始化示例数据(同方案一) List<Position> listA = Arrays.asList( new Position("ACC1", "20-Jan-23", "1", "open"), new Position("ACC1", "20-Jan-23", "2", "closing"), new Position("ACC2", "20-Jan-23", "1", "open"), new Position("ACC2", "20-Jan-23", "2", "closing"), new Position("ACC3", "20-Jan-23", "1", "open"), new Position("ACC3", "20-Jan-23", "2", "closing") ); List<Position> listB = Arrays.asList( new Position("ACC1", "20-Jan-23", "1", "open"), new Position("ACC1", "20-Jan-23", "2", "closing"), new Position("ACC2", "20-Jan-23", "1", "open"), new Position("ACC2", "20-Jan-23", "2", "closed"), new Position("ACC3", "20-Jan-23", "1", "open") ); // 手动分组ListA Map<String, List<Position>> groupA = new HashMap<>(); for (Position p : listA) { groupA.computeIfAbsent(p.getAccount(), k -> new ArrayList<>()).add(p); } // 手动分组ListB并转为Set Map<String, Set<Position>> groupB = new HashMap<>(); for (Position p : listB) { groupB.computeIfAbsent(p.getAccount(), k -> new HashSet<>()).add(p); } // 筛选符合条件的账户 Set<String> validAccounts = new HashSet<>(); for (Map.Entry<String, List<Position>> entry : groupA.entrySet()) { String account = entry.getKey(); List<Position> posA = entry.getValue(); Set<Position> posB = groupB.get(account); if (posB == null || posA.size() != posB.size()) { continue; } boolean allMatch = true; for (Position p : posA) { if (!posB.contains(p)) { allMatch = false; break; } } if (allMatch) { validAccounts.add(account); } } System.out.println("符合条件的账户:" + validAccounts); // 输出 [ACC1] } }
效率说明
两种方案的时间复杂度均为O(n + m)(n、m分别为ListA和ListB的元素数量),分组操作是线性遍历,匹配操作基于Set的O(1)查询,整体属于高效实现,适合处理大规模数据。
内容的提问来源于stack exchange,提问作者Enthu Leo
相关产品推荐
相关产品推荐

