Java 8函数样式用索引进行迭代

Igo*_*nko 6 functional-programming java-8 java-stream

我一直在练习java 8流和功能风格.有时我尝试使用流来解决一些编程难题.在这段时间里,我发现了一类我不知道如何用流来解决的任务,只有经典的方法.

这种任务的一个例子是:给定一个数字数组,找到元素的索引,它将使数组左边部分的总和低于零.例如,对于数组[1, 2, 3, -1, 3, -10, 9]答案将是5

我的第一个想法是使用,IntStream.generate(0, arr.length)...但后来我不知道如何累积值并同时意识到索引.

所以问题是:

  • 有可能以某种方式在流上累积值然后进行有条件退出吗?
  • 什么是并行执行?它不适合寻找我们需要了解元素顺序的索引的问题.

Ale*_* C. 5

我怀疑你的任务非常适合流.您正在寻找的是典型的扫描左操作,其本质上是顺序操作.

例如,想象一下管道中的以下元素:[1, 2, -4, 5].并行执行可以将其分成两个子部分即[1, 2][-4, 5].那你会用它们做什么?您不能独立概括他们,因为这将产量[3][1],然后你失去的事实1 + 2 - 4 < 0得到尊重.

因此,即使你编写了一个跟踪索引和总和的收集器,它也无法并行执行(我怀疑你甚至可以从中受益)但你可以想象这样的收集器可以顺序使用:

public static Collector<Integer, ?, Integer> indexSumLeft(int limit) {
        return Collector.of(
                () -> new int[]{-1, 0, 0},
                (arr, elem) -> {
                    if(arr[2] == 0) {
                        arr[1] += elem;
                        arr[0]++;
                    }
                    if(arr[1] < limit) {
                        arr[2] = 1;
                    }

                },
                (arr1, arr2) -> {throw new UnsupportedOperationException("Cannot run in parallel");},
                arr -> arr[0]

        );
    }
Run Code Online (Sandbox Code Playgroud)

一个简单的用法:

int index = IntStream.of(arr).boxed().collect(indexSumLeft(0));
Run Code Online (Sandbox Code Playgroud)

这仍将遍历管道的所有元素,因此效率不高.

Arrays.parallelPrefix如果数据源是数组,您也可以考虑使用它.只需计算其上的部分和,然后使用流来查找总和低于限制的第一个索引.

Arrays.parallelPrefix(arr, Integer::sum);
int index = IntStream.range(0, arr.length)
                     .filter(i -> arr[i] < limit)
                     .findFirst()
                     .orElse(-1);
Run Code Online (Sandbox Code Playgroud)

这里也计算了所有的部分和(但是并行).

简而言之,我会使用一个简单的for循环.