簡體   English   中英

如何一次迭代 Stream 的兩項?

[英]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 可以在任意點拆分,以實現並行化/緩存;
  • 歸約操作與加法具有相同的基本語義(換句話說,兩個順序項的順序不應該對歸約結果產生影響,歸約操作本身可以任意拆分,總體結果將是相同的)。

如果您真的想以您建議的方式處理 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM