[英]Java 8 streams: process every possible pair of elements from list
我有一個任意類的元素Collection
。 我想迭代遍歷集合並使用元素和集合中的每個其他元素逐個執行一些操作(不包括元素本身)。 為簡單起見,讓它成為List<Integer>
:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
對於for
循環,它將是:
for (Integer i : list) {
for (Integer j : list) {
if (!i.equals(j)) System.out.println(i * 2 + j); //just for example
}
}
問題是如何使用Stream API執行此操作 ?
這就是我所得到的:
list.stream().forEach(i ->
list.stream().forEach(j -> {
if (!i.equals(j)) System.out.println(i * 2 + j);
})
);
但它看起來並不比嵌套循環好。 有更優雅的方式嗎?
您可以使用flatMap
操作執行此操作:
list.stream()
.flatMap(i -> list.stream().filter(j -> !i.equals(j)).map(j -> i * 2 + j))
.forEach(System.out::println);
此代碼正在創建輸入列表的Stream。 它使用同一列表創建的流平面映射列表的每個元素,其中當前元素被過濾掉,並且此新列表的每個元素都是i * 2 + j
操作的結果。
然后將所有元素打印到控制台。
您可以通過事先映射到int
值來避免對象比較,例如
list.stream().mapToInt(Integer::intValue)
.flatMap(i -> list.stream().filter(j -> j!=i).mapToInt(j -> i*2 + j))
.forEach(System.out::println);
但實際上,您正在對不變的事物執行條件運算和相等性檢查。 由於整個操作依賴於源列表而不改變其中間的內容,因此您可以首先簡單地生成配對列表索引:
final int end=list.size();
IntStream.range(0, end).flatMap(i ->
IntStream.concat(IntStream.range(0, i), IntStream.range(i+1, end))
.map(j -> list.get(i) * 2 + list.get(j)))
.forEach(System.out::println);
如果你不想計算數值但是為對創建一個對象,由於IntStream
沒有flatMapToObj
操作,它會變得有點復雜,所以我們需要mapToObj
和flatMap
的組合(除非我們使用boxed
)。 因此,構建一個雙長度數組示例如下:
IntStream.range(0, end).mapToObj(i ->
IntStream.concat(IntStream.range(0, i), IntStream.range(i+1, end))
.mapToObj(j -> new int[]{ list.get(i), list.get(j)}))
.flatMap(Function.identity())
.forEach(a -> System.out.println(a[0]*2+a[1]));
當然,對於像[ 1, 2, 3, 4, 5 ]
這樣簡單的列表,我們可以首先使用IntStream.rangeClosed(1, 5)
,而不處理List
:
IntStream.rangeClosed(1, 5).flatMap(i ->
IntStream.concat(IntStream.range(1, i), IntStream.rangeClosed(i+1, 5))
.map(j -> i*2 + j))
.forEach(System.out::println);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.