【问题标题】:How to convert nested loops to nested Streams? [duplicate]如何将嵌套循环转换为嵌套流? [复制]
【发布时间】:2017-08-03 12:13:51
【问题描述】:

假设我有一个 int 数组,我想找到总和为零的所有对。在过去,我会做这样的事情:

public static int count(int[] a) {
    int cnt = 0;
    int N = a.length;
    for (int i = 0; i < N; i++) {
        for (int j = i + 1; j < N; j++) {

        if (a[i] + a[j] == 0) {
            cnt++;
        }
       }
    }
    return cnt;
    }

现在我在将其转换为流时遇到了一些问题。

我尝试了以下方法,但得到了 IllegalStateException:

final IntStream stream1 = Arrays.stream(a);
final IntStream stream2 = Arrays.stream(a);
long res = stream1.flatMap(i -> stream2.filter(j -> (j + i == 0))).count();

【问题讨论】:

  • IllegalStateException 不是我的问题。我明白那个。这是我难以将嵌套的 for 转换为流的结果。我的问题是如何转换嵌套的流
  • 请编辑问题,在这种情况下我会重新打开
  • @MLeiria 我投票支持重新开放并更改标题

标签: java arrays java-8 java-stream


【解决方案1】:

stream2.filter 更改为 Arrays.stream(a) - 当您第二次尝试处理它时,Stream 将被关闭。

但无论如何你都没有正确计数,应该是:

 IntStream.range(0, a.length)
          .flatMap(x -> Arrays.stream(a).skip(x + 1).filter(j -> j + a[x] == 0))
          .count();

【讨论】:

  • 就是这样!!!谢谢。不知道skip。仍然对 Java 8 感兴趣(顺便说一句,这很棒)
  • 我明白了。谢谢
  • 当然,@尤金。答案中的好东西。
【解决方案2】:

Streams 是不可重复使用的,因此您无法定义一次并继续重复使用。这就是为什么将它们存储在变量中被认为是一种不好的做法。

您需要在现场创建它们:

long res = Arrays.stream(a)
  .flatMap(i -> Arrays.stream(a).filter(j -> (j + i == 0)))
  .count();

另外,为了充分体现提供的实现并避免重复,您需要在每个嵌套的Stream 开头添加skip 一些元素:

long res = IntStream.range(0, a.length)
  .flatMap(i -> Arrays.stream(a).skip(i + 1).filter(j -> (j + a[i] == 0)))
  .count();

如果您想将它们提取到变量中,您需要使用Supplier,它将作为我们Streams 的工厂。每个get 调用都会创建一个新的Stream 实例:

final Supplier<IntStream> s = () -> Arrays.stream(a);
long res = s.get()
  .flatMap(i -> s.get().filter(j -> (j + i == 0)))
  .count();

【讨论】:

  • 谢谢。它的诀窍在于流方法重复计数。在嵌套的 for 中,内部循环比外部循环领先一步,因此它不会重复计数。例如,如果int[] a = new int[]{1,2,3,4,-3,5,-5}; 嵌套的 for 给出的结果为 2,这是正确的,因为只有两个元素 (3, -3) 和 (5, -5) 但流给出的结果为 4
  • @MLeiria 我会更新答案
猜你喜欢
  • 2021-12-30
  • 2018-03-02
  • 2019-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多