我正在寻找一种方法来实现非终端分组操作,这样内存开销会很小。Java Streams - 有效地对已排序流上的项目进行分组
例如,考虑distinct()。在一般情况下,它别无选择,只能收集所有不同的项目,然后才将其转发。但是,如果我们知道输入流已经排序,那么可以使用最少的内存“即时”完成操作。
我知道我可以实现这个迭代器使用迭代器包装和我自己实现分组逻辑。有没有更简单的方法来实现这个使用流API而不是?
- 编辑 -
我找到了一种方法来虐待Stream.flatMap(..)来实现这一目标:
private static class DedupSeq implements IntFunction<IntStream> {
private Integer prev;
@Override
public IntStream apply(int value) {
IntStream res = (prev != null && value == prev)? IntStream.empty() : IntStream.of(value);
prev = value;
return res;
}
}
然后:
IntStream.of(1,1,3,3,3,4,4,5).flatMap(new DedupSeq()).forEach(System.out::println);
哪打印:
1
3
4
5
随着一些更改,可以使用相同的技术进行任何种类的高效内存有效的序列分组。无论如何,我不太喜欢这个解决方案,而且我正在寻找更自然的东西(例如像绘图或筛选工作的方式)。此外,我在此打破契约,因为提供给flatMap(..)的函数是有状态的。
您总是可以使用'.filter(someSet ::添加)',但你有没有尝试过,并将这种解决方案的性能与普通的'distinct()'进行比较?另外,你会说“在一般情况下”,但是可能会有一个优化的实现方式,即Stream'_is_' ORDERED',正好(或者更准确地说,是它的底层'Spliterator') – fge
@fge:我不确定那里有任何优化。代码: IntStream.range(0,100000000).distinct()。forEach(x - > {}); 内存不足,尽管潜在的Spliterator报告自己是ORDERED。 –
你用'.forEachOrdered()'试过了吗? – fge