如何使用 Java Streams 替代嵌套 for 循环筛选两数之和的元素?
实现方案
常规筛选(通用场景)
直接在外层流的filter中用anyMatch判断第二个列表是否存在匹配项,不需要手写嵌套循环,完全对应“从array1筛选符合条件元素”的语义:
// Java 16 及以上版本写法 List<Integer> array3 = array1.stream() .filter(x -> array2.stream().anyMatch(y -> x + y == 30)) .toList();
Java 8 等低版本改用收集器汇总结果即可:
// 需提前导入 java.util.stream.Collectors List<Integer> array3 = array1.stream() .filter(x -> array2.stream().anyMatch(y -> x + y == 30)) .collect(Collectors.toList());
anyMatch本身是短路操作,找到第一个符合条件的y就会终止内层遍历,不会跑完整个array2。这种写法下每个符合条件的x只会在结果中出现一次,是筛选类需求的标准行为。
基于你给出的测试数据,运行结果为:[20, 17, 12, 24]
严格对齐原循环逻辑
你提供的嵌套for循环有个隐含行为:如果array2里有多个y都能和同一个x相加等于30,这个x会被重复添加多次。如果需要完全复刻原循环的输出(包括重复元素),可以用flatMap实现:
List<Integer> array3 = array1.stream() .flatMap(x -> array2.stream() .filter(y -> x + y == 30) .map(y -> x) ) .collect(Collectors.toList());
每匹配到一对(x,y),就会向结果中添加一次x,和原嵌套循环的执行效果完全一致。
大数据量优化
如果两个列表元素量较大,嵌套遍历的时间复杂度为O(n*m)。可以先把array2对应的目标补数存入Set,用哈希匹配把时间复杂度降到O(n+m),全程依然可以用Stream实现:
Set<Integer> targetSet = array2.stream() .map(y -> 30 - y) .collect(Collectors.toSet()); List<Integer> array3 = array1.stream() .filter(targetSet::contains) .collect(Collectors.toList());
内容的提问来源于stack exchange,提问作者Luk
相关产品推荐
相关产品推荐

