[英]Using the same list with streams twice in Java
我必須用流完成這個簡單的操作:給出一個列表,得到總和和前20個元素的總和。
這就是我的想法
IntStream stream = obj.stream().mapToInt(d->d.getInt());
stream.limit(20).sum() / stream.sum();
但是我不能這樣做,因為我被告知我不能重復使用流,所以..我嘗試了以下內容:
List<Integer> counts = obj.stream()
.mapToInt(d -> d.getInt())
.boxed().collect(Collectors.toList());
counts.stream().limit(20).sum() / counts.stream().sum();
但是我被告知我不能在Stream上使用sum,所以我需要再次mapToInt用於這個簡單操作的左右兩側。
有沒有辦法使用流以更優雅和簡潔的方式執行此操作?
在單個並行傳遞中有一種很酷的方法,但不使用流。
int[] nums = obj.stream().mapToInt(Integer::intValue).toArray();
Arrays.parallelPrefix(nums, Integer::sum);
int sumOfFirst20 = nums[19];
int sumOfAll = nums[nums.length-1];
parallelPrefix方法將在適當的位置計算數組上指定函數(此處為plus)的部分和的序列。 所以第一個元素是a0; 第二個是a0 + a1,第三個是a0 + a1 + a2等。
您可以將它們轉換為帶有toArray()
的int[]
,而不是在List<Integer>
中收集數字。 這樣,代碼更緊湊,您不必一直打包和取消打包,並且可以將int[]
直接轉換為IntStream
。
int[] nums = obj.stream().mapToInt(d -> d.getInt()).toArray();
IntStream.of(nums).limit(20).sum() / IntStream.of(nums).sum();
沒有必要使事情過於復雜。 只需從列表中獲取兩次流:
int totalSum = obj.stream().mapToInt(i -> i).sum();
int first20 = obj.stream().limit(20).mapToInt(i -> i).sum();
是的,它會在列表中進行兩次傳遞(第二次僅用於20個第一個元素,所以沒什么大不了的),所以我希望這是他們想要你做的。 它簡單,高效且易讀。
要在一次通過中執行此操作,您可以使用收集器。 舉個例子,你可以這樣做:
Map<Boolean, Integer> map = IntStream.range(0, obj.size())
.boxed()
.collect(partitioningBy(i -> i < 20,
mapping(i -> obj.get(i),
summingInt(i -> i))));
int first20 = map.get(true);
int totalSum = map.get(true) + map.get(false);
基本上,您首先流式傳輸索引。 然后為每個指標; 你將它們分成兩個列表中的地圖,一個用於20個第一個索引,另一個用於另一個列表; 產生Map<Boolean, List<Integer>>
。
然后將每個索引映射到原始List
值(使用mapping
收集器)。
最后,通過將每個List<Integer>
的值合並為一個Integer
轉換每個List<Integer>
。 然后你得到總和。
自定義收集器的另一種解決方法:
public static Collector<Integer, Integer[], Integer[]> limitSum(int limit, List<Integer> list) {
return Collector.of(() -> new Integer[]{0, 0},
(a, t) -> { a[0] += list.get(t); if(t < limit) a[1] += list.get(t); },
(a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
a -> a);
}
以及用法示例:
List<Integer> obj = Stream.iterate(0, x -> x + 1).limit(5).collect(toList()); //[0, 1, 2, 3, 4]
Integer[] result = IntStream.range(0, obj.size())
.boxed()
.collect(limitSum(4, obj));
System.out.println(Arrays.toString(result)); //[10, 6]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.