[英]How can I iterate over two items of a Stream at once?
我有一个向量列表,我想在它们之间使用 stream 画线(目标是一条穿过所有点的连续线)。 目前,我的设置如下所示:
l.points().stream()
.map(v -> vectorOfTile((int) v.x, (int) v.y))
.reduce(l.points().get(0), (v1, v2) -> {
line(v1.x, v1.y, v2.x, v2.y);
return v2;
});
不幸的是,这明显滥用了 reduce 方法,因为我改为使用它来迭代每个项目两次,一次用于 stream 中的每个邻居。
有没有办法在 stream 中使用一些二元运算符来实现相同的行为? 我该如何实施这样的运营商?
正如@Piotr 所指出的,使用通用 for 循环可能只是 go 的方法。 我现在对这个问题的解决方案如下:
PVector[] a = l.points().stream().map(v -> vectorOfTile((int) v.x, (int) v.y)).toArray(PVector[]::new);
for (int i = 0; i < a.length - 1; i++) {
line(a[i].x, a[i].y, a[i + 1].x, a[i + 1].y);
}
通常,stream 范式是建立在一些不太适合 stream 中的项目分组目的的基本思想之上的。 stream 范例通常假设:
如果您真的想以您建议的方式处理 Stream 中的项目,那么 - 无论是好习惯还是其他方式(剧透:它是“否则”......) - 您可以编写如下方法:
public static <T, V> void forEachCombined(Stream<T> sourceStream, BiFunction<T, T, V> combiner, Consumer<V> op) {
assert(!sourceStream.isParallel());
T[] pair = (T[]) new Object[2];
int[] pos = new int[1];
sourceStream.forEachOrdered(obj -> {
pair[pos[0]] = obj;
if (++pos[0] == 2) {
V combined = combiner.apply(pair[0], pair[1]);
op.accept(combined);
pos[0] = 0;
}
});
}
请注意,我们必须将 go 调整到一些丑陋的长度,以允许一次调用 forEachOrdered() 以记住前一次调用中的 state,这是有充分理由的:它通常打破了函数式编程范式,以这种方式在单独的调用之间创建“状态”。 但结果是您可以采用顺序对并组合成点,如下所示:
Stream<Integer> coordStream = Stream.of(1, 2, 3, 4);
forEachCombined(coordStream, Point::new, point -> {
// ... Do something with 'point'
});
对于调用者,只要将 forEachCombined() 方法隐藏在实用程序 class 中,并带有警告“不要在家尝试这个”,那么生成的语法可以说还不错。 不过,它确实打破了许多人认为好的设计原则。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.