Java 如何一次迭代流的两个项?

Java 如何一次迭代流的两个项?,java,java-stream,processing,Java,Java Stream,Processing,我有一个向量列表,在这些向量之间我想用一个流来画线(目标是一条穿过所有点的连续线)。 当前,我的设置如下所示: 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);

我有一个向量列表,在这些向量之间我想用一个流来画线(目标是一条穿过所有点的连续线)。 当前,我的设置如下所示:

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方法的滥用,因为我使用reduce方法对每个项迭代两次,对流中的每个邻居迭代一次

有没有办法在流中使用一些二进制运算符来实现相同的行为?我怎样才能雇用这样的操作员


正如@Piotr所指出的,使用泛型for循环可能就是一条出路。我现在的解决办法如下:

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<Integer> coordStream = Stream.of(1, 2, 3, 4);

    forEachCombined(coordStream, Point::new, point -> {
        // ... Do something with 'point'
    });
PVector[]a=l.points().stream().map(v->vectorOfTile((int)v.x,(int)v.y)).toArray(PVector[]::new);
对于(int i=0;i
一般来说,流范式是建立在一些基本思想之上的,这些基本思想并不完全符合流中项目分组的目的。流范式通常假定:

  • 为了并行化/缓存的目的,可以在任意点拆分流
  • 归约操作与加法操作具有相同的基本语义(换句话说,两个连续项的顺序不应对归约结果产生影响,归约操作本身可以任意拆分,总体结果相同)
如果您真的希望以您建议的方式处理流中的项目,那么——无论是良好实践还是其他方式(spoiler:it's'others'…)——您可以编写如下方法:

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;
        }
    });
}
publicstaticvoid-forEachCombined(流源流、双功能组合器、用户操作){
断言(!sourceStream.isParallel());
T[]对=(T[])新对象[2];
int[]pos=新的int[1];
sourceStream.forEachOrdered(obj->{
对[pos[0]]=obj;
如果(++pos[0]==2){
V组合=组合器。应用(对[0],对[1]);
op.accept(合并);
pos[0]=0;
}
});
}
请注意,为了让对forEachOrdered()的一次调用能够记住上一次调用的状态,我们必须走一些难看的路,这是有充分理由的:它通常会打破函数式编程范式,以这种方式在单独的调用之间创建“状态”。但结果是,您可以采用顺序对并按如下方式组合成点:

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<Integer> coordStream = Stream.of(1, 2, 3, 4);

    forEachCombined(coordStream, Point::new, point -> {
        // ... Do something with 'point'
    });
Stream-coordStream=Stream.of(1,2,3,4);
forEachCombined(coordStream,Point::new,Point->{
//…用“点”做点什么
});

对于调用方来说,只要forEachCombined()方法隐藏在一个带有警告“不要在家中尝试此操作”的实用程序类中,那么生成的语法可以说还不错。不过,它确实打破了许多人认为是好的设计原则。

我认为您的问题假设流既有顺序又有顺序(有些是,有些不是)。我猜API只支持适用于所有类型流的操作,所以可能没有API可以从流中获取“一对相邻项”,因为它没有为并行或无序流定义好?也许你可以做一个普通的for循环?这会更容易吗?@Piotr说得好——我主要是在处理顺序流,所以这是我没有考虑过的。我想你可能是对的,我最好的方式是常规的for循环。我刚刚将映射的流转换为数组,它以相当清晰的方式执行相同的操作。非常感谢。让我想起了学校的往事。是的,当处理同一集合中多个元素的序列时,使用常规for循环更容易。试图使用流将奇数计数和偶数计数相加,作为同一流中的两个不同结果。流不能很好地访问多个元素的序列。