Functional programming 使用索引进行迭代的Java8函数样式
我已经练习Java8流和函数式有一段时间了。 有时,我尝试使用流解决一些编程难题。 在这段时间里,我发现了一类任务,我不知道如何用流来解决,只知道用经典方法 此类任务的一个示例是: 给定一个数字数组,找到元素的索引,使数组左半部分的和小于零。 e、 g.对于数组Functional programming 使用索引进行迭代的Java8函数样式,functional-programming,java-8,java-stream,Functional Programming,Java 8,Java Stream,我已经练习Java8流和函数式有一段时间了。 有时,我尝试使用流解决一些编程难题。 在这段时间里,我发现了一类任务,我不知道如何用流来解决,只知道用经典方法 此类任务的一个示例是: 给定一个数字数组,找到元素的索引,使数组左半部分的和小于零。 e、 g.对于数组[1,2,3,-1,3,-10,9]答案将是5 我的第一个想法是使用IntStream.generate(0,arr.length)…,但我不知道如何累积值,同时知道索引 因此,问题是: 是否有可能以某种方式在流上累积值,然后有条件地退
[1,2,3,-1,3,-10,9]
答案将是5
我的第一个想法是使用IntStream.generate(0,arr.length)…
,但我不知道如何累积值,同时知道索引
因此,问题是:
- 是否有可能以某种方式在流上累积值,然后有条件地退出
- 那么并行执行是什么呢?这不适合在需要了解元素顺序的地方查找索引的问题
int[] input = {1, 2, 3, -1, 3, -10, 9};
System.out.println(IntStreamEx.of(
IntStreamEx.of(input).scanLeft(Integer::sum)).indexOf(x -> x < 0));
// prints OptionalLong[5]
int[]input={1,2,3,-1,3,-10,9};
System.out.println(intstreamx.of(
intstreamx.of(input).scanLeft(Integer::sum)).indexOf(x->x<0);
//打印可选长度[5]
它使用操作来计算前缀和的数组,然后使用操作在该数组上搜索。当
indexOf
短路时,scanLeft
操作将处理整个输入,并创建一个与输入长度相同的中间数组,这在以命令式方式解决相同问题时是完全不必要的。我怀疑您的任务是否适合流。您正在寻找的是一个典型的左扫操作,它本质上是一个顺序操作
例如,想象管道中的以下元素:[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]
);
}
这仍然会遍历管道的所有元素,因此效率不高
也可以考虑使用<代码>数组。如果数据源是数组,则并行前缀< /C>。只需计算它上面的部分和,然后使用一个流来找到第一个索引,其中和低于限制
Arrays.parallelPrefix(arr, Integer::sum);
int index = IntStream.range(0, arr.length)
.filter(i -> arr[i] < limit)
.findFirst()
.orElse(-1);
parallelPrefix(arr,Integer::sum);
int index=IntStream.range(0,arr.length)
.filter(i->arr[i]scanleet
操作:
public static <T> StreamEx<T> scanLeft(StreamEx<T> input, BinaryOperator<T> operator) {
return input.headTail((head, tail) ->
scanLeft(tail.mapFirst(cur -> operator.apply(head, cur)), operator)
.prepend(head));
}
这同样适用于无限流(例如,随机数流):
streamx ints=intstreamx.of(new Random(),-100100)
.peek(System.out::println).boxed();
intidx=scanleet(ints,Integer::sum).indexOf(x->x<0);
这将一直运行,直到累积和变为负数并返回相应元素的索引。流API几乎不可能出现此问题,因为此问题需要跟踪也绑定到元素顺序的非局部状态(所有前缀元素的总和)。流API的设计目的是使并行处理与顺序处理一样简单,但这种操作本质上是顺序的…可能与和重复。很好。我不知道我的名字。非常感谢。
public static <T> StreamEx<T> scanLeft(StreamEx<T> input, BinaryOperator<T> operator) {
return input.headTail((head, tail) ->
scanLeft(tail.mapFirst(cur -> operator.apply(head, cur)), operator)
.prepend(head));
}
scanLeft(StreamEx.of(1, 2, 3, -1, 3, -10, 9), Integer::sum).indexOf(x -> x < 0);
StreamEx<Integer> ints = IntStreamEx.of(new Random(), -100, 100)
.peek(System.out::println).boxed();
int idx = scanLeft(ints, Integer::sum).indexOf(x -> x < 0);