[英]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.