使用Java 8 Stream API查找列表中哪些数字总和为特定数字。

huangapple go评论90阅读模式
英文:

Find which number in a list sum up to a certain number Using Java 8 Stream API

问题

我已经尝试使用Java 8找到和等于给定数字的数字对的总和。我们如何改进这个逻辑?

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 
12 4 

我得到的输出:

16 0 
4 12 
0 16 
12 4 
英文:

I have tried to find the sum of pair which is equals to given number using java 8. how can we improve the logic?

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

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

Expected output:

16 0 
12 4 

Output I am getting:

16 0 
4 12 
0 16 
12 4  

答案1

得分: 2

static void printPairs(List list, int sum){
list
.stream()
.flatMap(i -> list.stream().filter(j -> i + j == sum && i < j))
.map(k -> k + ", " + (sum - k))
.distinct()
.forEach(System.out::println);
}

英文:
    static void printPairs(List&lt;Integer&gt; list, int sum){
        list
            .stream()
            .flatMap(i -&gt; list.stream().filter(j -&gt; i + j == sum &amp;&amp; i &lt; j))
            .map(k -&gt; k + &quot;, &quot; + (sum-k))
            .distinct()
            .forEach(System.out::println);
    }

答案2

得分: 1

只需要对这对数进行排序即可。这些对数之所以重复是因为对数中的数字顺序不同。

List<Integer> listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
Set<String> sumPair = listOfNumbers.stream()
        .flatMap(i -> listOfNumbers.stream()
                .filter(p -> (i + p) == 16 && listOfNumbers.indexOf(p) != listOfNumbers.indexOf(i))
                .map(p -> i < p ? (p + " " + i) : (i + " " + p)))
        .collect(Collectors.toSet());
for (String pair : sumPair) {
    System.out.println(pair);
}

输出:

12 4
16 0

此外,我简化了使用字符串流而不是整数数组的方式。但你可以根据需要进行调整。

主要问题是 "12 4" 和 "4 12" - 相同数字的一对,但顺序不同会被Set视为不同的值,并且会添加两次。

更新...
还有一件事可以做,那就是使用 Stream.distinct 而不是使用 Set。

List<Integer> listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0, 12);
listOfNumbers.stream()
        .flatMap(i -> listOfNumbers.stream().filter(j -> (i + j) == 16 && i < j).map(k -> i + " " + k))
        .distinct().forEach(System.out::println);

这会得到相同的输出:

12 4
16 0
英文:

It seems, you just need to SORT the pair. The pairs are duplicated just because of the reverse order of the numbers in the pair.

		List&lt;Integer&gt; listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
		Set&lt;String&gt; sumPair = listOfNumbers.stream()
				.flatMap(i -&gt; listOfNumbers.stream()
						.filter(p -&gt; (i + p) == 16 &amp;&amp; listOfNumbers.indexOf(p) != listOfNumbers.indexOf(i))
						.map(p -&gt; i &lt; p ? (p + &quot; &quot; + i) : (i + &quot; &quot; + p)))
				.collect(Collectors.toSet());
		for (String pair : sumPair) {
			System.out.println(pair);
		}

Output:

12 4
16 0

Also, I simplified to use the stream of strings instead of Integer array.
But you can tweak it as you like.

The main problem was "12 4" and "4 12" - the pair of same numbers but in reverse order will be different values for Set, and will get added twice.

Update...
One more thing that can be done is using Stream.distinct, instead of using a Set.

List&lt;Integer&gt; listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0, 12);
listOfNumbers.stream()
		.flatMap(i -&gt; listOfNumbers.stream().filter(j -&gt; (i + j) == 16 &amp;&amp; i &lt; j).map(k -&gt; i + &quot; &quot; + k))
		.distinct().forEach(System.out::println);

This gives the same output

12 4
16 0

答案3

得分: 0

你可以利用两个集合包含相同元素而不考虑顺序的事实,来判断它们是否相等。根据文档中的描述:

如果指定的对象也是一个集合,两个集合的大小相同,并且指定集合的每个成员都包含在此集合中(或等效地,此集合的每个成员都包含在指定集合中),则返回true。

收集到一个Set<Set<Integer>>中:

List<Integer> listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
Set<Set<Integer>> sumPair = listOfNumbers.stream()
        .flatMap(i -> listOfNumbers.stream()
                .filter(p -> (i + p) == 16 && listOfNumbers.indexOf(p) != listOfNumbers.indexOf(i))
                .map(p -> new HashSet<>(Arrays.asList(p, i))))
        .collect(Collectors.toSet());
for (Set<Integer> integers : sumPair) {
  for (Integer val : integers) {
    System.out.print(val + " ");
  }
  System.out.println();
}

请注意,HashSet 是无序的,所以如果顺序重要的话,你可能需要进行排序。

个人建议使用自定义类来实现,比如 Pair

public class Pair {

  private final int a;
  private final int b;

  public Pair(int a, int b) {
    this.a = a;
    this.b = b;
  }

  @Override
  public int hashCode() {
    return Integer.hashCode(this.a + this.b);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof Pair pair)) {
      return false;
    }
    return (this.a == pair.a && this.b == pair.b) || (this.a == pair.b && this.b == pair.a);
  }

  @Override
  public String toString() {
    return this.a + " " + this.b;
  }
}

然后找到并收集成对的元素可以这样实现:

List<Integer> listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
Set<Pair> sumPair = listOfNumbers.stream()
        .flatMap(i -> listOfNumbers.stream()
                .filter(p -> (i + p) == 16 && listOfNumbers.indexOf(p) != listOfNumbers.indexOf(i))
                .map(p -> new Pair(i, p)))
        .collect(Collectors.toSet());
for (Pair pair : sumPair) {
  System.out.println(pair);
}
英文:

You can take advantage of the fact that 2 sets are considered equal, if they contain the same element, regardless of the order. From the docs:

> Returns true if the specified object is also a set, the two sets have the same size, and every member of the specified set is contained in this set (or equivalently, every member of this set is contained in the specified set).

Collect to a Set&lt;Set&lt;Integer&gt;&gt;

List&lt;Integer&gt; listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
Set&lt;Set&lt;Integer&gt;&gt; sumPair = listOfNumbers.stream()
        .flatMap(i -&gt; listOfNumbers.stream()
                .filter(p -&gt; (i + p) == 16 &amp;&amp; listOfNumbers.indexOf(p) != listOfNumbers.indexOf(i))
                .map(p -&gt; new HashSet&lt;&gt;(Arrays.asList(p, i))))
        .collect(Collectors.toSet());
for (Set&lt;Integer&gt; integers : sumPair) {
  for (Integer val : integers) {
    System.out.print(val + &quot; &quot;);
  }
  System.out.println();
}

Note that HashSet is unordered, so you may need to sort, if it matters.

Personally i would do it with a custom class, though. Let's say Pair:

public class Pair {

  private final int a;
  private final int b;

  public Pair(int a, int b) {
    this.a = a;
    this.b = b;
  }

  @Override
  public int hashCode() {
    return Integer.hashCode(this.a + this.b);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof Pair pair)) {
      return false;
    }
    return (this.a == pair.a &amp;&amp; this.b == pair.b) || (this.a == pair.b &amp;&amp; this.b == pair.a);
  }

  @Override
  public String toString() {
    return this.a + &quot; &quot; + this.b;
  }
}

Then finding and collecting the pairs would be like this:

List&lt;Integer&gt; listOfNumbers = Arrays.asList(15, 12, 4, 16, 9, 8, 24, 0);
Set&lt;Pair&gt; sumPair = listOfNumbers.stream()
        .flatMap(i -&gt; listOfNumbers.stream()
                .filter(p -&gt; (i + p) == 16 &amp;&amp; listOfNumbers.indexOf(p) != listOfNumbers.indexOf(i))
                .map(p -&gt; new Pair(i, p)))
        .collect(Collectors.toSet());
for (Pair pair : sumPair) {
  System.out.println(pair);
}

答案4

得分: 0

你目前用来找到和等于给定数字的配对的逻辑是功能性的,但它有一些低效和冗余的输出配对。为了改进这个逻辑,你可以避免冗余的配对并提高性能。下面是一个优化过的版本:

public class Main {
    public static void main(String[] args) {
        List<Integer> listOfNumbers = Arrays.asList(new Integer[]{15, 12, 4, 16, 9, 8, 24, 0});
        int targetSum = 16;

        Set<Integer[]> sumPair = findPairsWithSum(listOfNumbers, targetSum);
        for (Integer[] integers : sumPair) {
            for (Integer val : integers) {
                System.out.print(val + " ");
            }
            System.out.println("");
        }
    }

    public static Set<Integer[]> findPairsWithSum(List<Integer> list, int targetSum) {
        Set<Integer> seen = new HashSet<>();
        Set<Integer[]> sumPair = new HashSet<>();

        for (Integer num : list) {
            int complement = targetSum - num;
            if (seen.contains(complement)) {
                Integer[] pair = {num, complement};
                Arrays.sort(pair);
                sumPair.add(pair);
            }
            seen.add(num);
        }
        return sumPair;
    }
}

在这个版本中,我们使用了一个名为 seen 的 HashSet 来存储我们迄今为止遇到的列表元素。当我们遍历列表时,我们检查补充数(目标和与当前数字之差)是否在 seen 集合中存在。如果存在,我们已经找到了一个总和等于 targetSum 的配对,并将配对添加到 sumPair 集合中。在添加之前对配对进行排序可以确保我们不会有重复的配对,比如 (4, 12) 和 (12, 4)。

这个解决方案降低了复杂性,并避免了冗余的输出配对。

英文:

Your current logic to find pairs whose sum equals a given number is functional, but it has some inefficiencies and redundant pairs in the output. To improve the logic, you can avoid redundant pairs and improve the performance. Here's an optimized version:

public class Main {
    public static void main(String[] args) {
        List&lt;Integer&gt; listOfNumbers = Arrays.asList(new Integer[]{15, 12, 4, 16, 9, 8, 24, 0});
        int targetSum = 16;

        Set&lt;Integer[]&gt; sumPair = findPairsWithSum(listOfNumbers, targetSum);
        for (Integer[] integers : sumPair) {
            for (Integer val : integers) {
                System.out.print(val + &quot; &quot;);
            }
            System.out.println(&quot;&quot;);
        }
    }

    public static Set&lt;Integer[]&gt; findPairsWithSum(List&lt;Integer&gt; list, int targetSum) {
        Set&lt;Integer&gt; seen = new HashSet&lt;&gt;();
        Set&lt;Integer[]&gt; sumPair = new HashSet&lt;&gt;();

        for (Integer num : list) {
            int complement = targetSum - num;
            if (seen.contains(complement)) {
                Integer[] pair = {num, complement};
                Arrays.sort(pair);
                sumPair.add(pair);
            }
            seen.add(num);
        }
        return sumPair;
    }
}

In this version, we use a HashSet called seen to store the elements of the list that we have encountered so far. As we iterate through the list, we check if the complement (the difference between the targetSum and the current number) is present in the seen set. If it is, we have found a pair that adds up to the targetSum, and we add the pair to the sumPair set. Sorting the pair before adding it ensures that we don't have duplicates like (4, 12) and (12, 4).

This solution reduces the complexity and avoids redundant pairs in the output.

huangapple
  • 本文由 发表于 2023年7月11日 14:27:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76659206.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定