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

如何优化Java 8 Stream API实现列表中和为指定值的数对查找

问题:Java 8 Stream查找和为指定值的不重复数对

我尝试使用Java 8 Stream API查找列表中和为指定值(此处为16)的数对,但当前输出出现了重复的反向数对(如12 4与4 12、16 0与0 16),期望得到无重复的目标数对结果,请问该如何优化现有逻辑?

原实现代码

List<Integer> listOfNumbers = Arrays.asList(new Integer []{15, 12, 4, 16, 9, 8, 24, 0});

Set<Integer[]> sumPair = listOfNumbers.stream()
        .flatMap(i -> listOfNumbers.stream()
                .filter(p -> (i + p) == 16 && listOfNumbers.indexOf(p) != listOfNumbers.indexOf(i))
                .map(p -> new Integer[] { i, p }))
        .collect(Collectors.toSet());
for (Integer[] integers : sumPair) {
    for (Integer val : integers) {
        System.out.print(val + " ");
    }
    System.out.println("");
}

实际输出

16 0 
4 12 
0 16 
12 4 

期望输出

16 0 
12 4 

优化方案

方法一:通过索引遍历避免反向数对

原逻辑遍历所有元素两两组合,导致正向和反向对都被收集。可以改为遍历索引,只处理当前索引之后的元素,这样每个数对只会被匹配一次:

List<Integer> listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
int targetSum = 16;

List<int[]> sumPair = IntStream.range(0, listOfNumbers.size())
        .boxed()
        .flatMap(i -> IntStream.range(i + 1, listOfNumbers.size())
                .filter(j -> listOfNumbers.get(i) + listOfNumbers.get(j) == targetSum)
                .mapToObj(j -> new int[]{listOfNumbers.get(i), listOfNumbers.get(j)}))
        .collect(Collectors.toList());

sumPair.forEach(pair -> System.out.println(pair[0] + " " + pair[1]));

方法二:使用自定义不可变数对类实现去重

Integer[]作为集合元素时,数组的equals和hashCode是基于对象引用的,无法识别内容相同的反向数组。可以定义一个不可变的数对类,标准化存储顺序并重写判断方法,让(a,b)和(b,a)被视为相等:

import java.util.Objects;

class Pair {
    private final int first;
    private final int second;

    public Pair(int first, int second) {
        // 标准化存储:让较小的数在前,较大的在后
        this.first = Math.min(first, second);
        this.second = Math.max(first, second);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Pair pair = (Pair) o;
        return first == pair.first && second == pair.second;
    }

    @Override
    public int hashCode() {
        return Objects.hash(first, second);
    }

    @Override
    public String toString() {
        return first + " " + second;
    }
}

修改后的Stream逻辑:

List<Integer> listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
int targetSum = 16;

Set<Pair> sumPair = listOfNumbers.stream()
        .flatMap(i -> listOfNumbers.stream()
                .filter(p -> i + p == targetSum && !i.equals(p))
                .map(p -> new Pair(i, p)))
        .collect(Collectors.toSet());

sumPair.forEach(System.out::println);

方法三:利用Set记录已处理元素

遍历过程中,用Set存储已经检查过的元素,找到符合条件的数对后,把补数加入Set,避免后续反向配对:

List<Integer> listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
int targetSum = 16;
Set<Integer> processed = new HashSet<>();

List<int[]> sumPair = listOfNumbers.stream()
        .filter(num -> !processed.contains(num))
        .flatMap(num -> {
            int complement = targetSum - num;
            if (listOfNumbers.contains(complement) && !num.equals(complement)) {
                processed.add(complement);
                return Stream.of(new int[]{num, complement});
            }
            return Stream.empty();
        })
        .collect(Collectors.toList());

sumPair.forEach(pair -> System.out.println(pair[0] + " " + pair[1]));

注:如果列表中存在重复元素(如两个8),需根据需求调整逻辑,比如是否允许8,8这类自身配对的数对。


内容的提问来源于stack exchange,提问作者ranjan kumar singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:42:49