正确的(虽然不是很容易)的方式来做到这一点是写自己的Spliterator
。常见的算法如下:
- 使用
stream.spliterator()
- 写自己的Spliterator推进可能做一些额外的操作时可能会占用现有的元素以现有的流Spliterator。
- 通过
StreamSupport.stream(spliterator, stream.isParallel())
- 委派创建基于您的spliterator一个新的流状
.onClose(stream::close)
close()
调用原始数据流。
编写好的并行处理好的分割器通常是非常不平凡的任务。但是,如果你不关心并行化,你可以继承AbstractSpliterator
这更简单。下面是一个例子,如何写一个新的流操作以给定位置删除一个元素:
public static <T> Stream<T> removeAt(Stream<T> src, int idx) {
Spliterator<T> spltr = src.spliterator();
Spliterator<T> res = new AbstractSpliterator<T>(Math.max(0, spltr.estimateSize()-1),
spltr.characteristics()) {
long cnt = 0;
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if(cnt++ == idx && !spltr.tryAdvance(x -> {}))
return false;
return spltr.tryAdvance(action);
}
};
return StreamSupport.stream(res, src.isParallel()).onClose(src::close);
}
这是最小的实现,它可以改善,表现出更好的性能和并行。
在我的StreamEx库中,我尝试通过headTail
来简化这种自定义流操作的添加。以下是如何使用StreamEx
做同样的:
public static <T> StreamEx<T> removeAt(StreamEx<T> src, int idx) {
// head is the first stream element
// tail is the stream of the rest elements
// want to remove first element? ok, just remove tail
// otherwise call itself with decremented idx and prepend the head element to the result
return src.headTail(
(head, tail) -> idx == 0 ? tail : removeAt(tail, idx-1).prepend(head));
}
你甚至可以支持与chain()
方法链接:
public static <T> Function<StreamEx<T>, StreamEx<T>> removeAt(int idx) {
return s -> removeAt(s, idx);
}
用例:
StreamEx.of("Java 8", "Stream", "API", "is", "not", "great")
.chain(removeAt(4)).forEach(System.out::println);
最后请注意,即使没有headTail
有一些使用StreamEx解决问题的方法。要删除你可以用越来越多的拉链具体指标,然后过滤和删除索引是这样的:
StreamEx.of(stream)
.zipWith(IntStreamEx.ints().boxed())
.removeValues(pos -> pos == idx)
.keys();
要折叠相邻重复还有的专门collapse
方法(它甚至并行化,相当不错!):
StreamEx.of(stream).collapse(Object::equals);
你的榜样需要有一个收集不流 - 如果你不知道,你可以删除最后一个元素的数量,流可以被多个线程处理,所以再次相邻的重复是不可能的。我认为你可以以某种方式去除例如仅限第七元素。 –
好吧,'distinct'以某种方式删除相邻的重复项,显然这是可能的。但我同意删除最后一个元素可能没有正确定义 – piotrek
'distinct'是一种简单的算法,它的工作方式与Linux'uniq'命令相同。所有你需要做的就是跟踪你之前看到的价值。如果当前值不同,请将其记录为先前的值。如果相同,则跳过此元素并继续。最多的情况下,您在任何时候都会查看两个连续的元素。您的要求假设“流”可能并非如此,直到您处理完“流”后才能发现。 – nickb