如何从 Stream 中提取两个元素根据他们的立场?例如,我试图从 Stream<String>
中提取元素 0 和 1(这些数字是任意的!) .一个天真的方法是这样的:
List<String> strings = Arrays.asList("s0", "s1", "s2", "s3", "s4");
Consumer<String> c0 = s -> System.out.println("c0.accept(" + s + ")");
Consumer<String> c1 = s -> System.out.println("c1.accept(" + s + ")");
strings.stream().skip(0).peek(c0).skip(1).peek(c1).findAny();
这会产生以下输出:
c0.accept(s0)
c0.accept(s1)
c1.accept(s1)
我明白这是因为s0
会进流,遇到skip(0)
, 然后 peek(c0)
(给出第一行)然后是 skip(1)
, 它将跳过这个元素,然后显然从流的开头继续下一个元素。
我以为我可以使用这些消费者来提取字符串,但是 c0
将被第二个元素覆盖:
String[] extracted = new String[2];
c0 = s -> extracted[0];
c1 = s -> extracted[1];
编辑:
这些是流的特征:
- 只有流,没有列表或数组
- 流可能是无限的
- 可以制作流sequential
最佳答案
鉴于您的限制,您可以结合 limit()
使用这样的自定义收集器:
public static <T, A, R> Collector<T, ?, R> collectByIndex(Set<Integer> wantedIndices,
Collector<T, A, R> downstream) {
class Acc {
int pos;
A acc = downstream.supplier().get();
}
return Collector.of(Acc::new, (acc, t) -> {
if(wantedIndices.contains(acc.pos++))
downstream.accumulator().accept(acc.acc, t);
}, (a, b) -> {throw new UnsupportedOperationException();}, // combining not supported
acc -> downstream.finisher().apply(acc.acc));
}
在这里Set<Integer> wantedIndices
是包含所需元素索引的集合(不限于 2)。用法:
Set<Integer> wantedIndices = new HashSet<>(Arrays.asList(1, 3));
Stream<String> input = Stream.of("s0", "s1", "s2", "s3", "s4");
List<String> result = input.limit(Collections.max(wantedIndices)+1)
.collect(collectByIndex(wantedIndices, Collectors.toList()));
// [s1, s3]
关于java - 从流中收集某些元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32481895/