相当于 Scala dropWhile [英] Equivalent of Scala dropWhile
问题描述
我正在努力寻找一种方法,根据谓词跳过流开头的某些元素.
I'm struggling to find a way to skip some elements at the beginning of a stream depending on a predicate.
像这样:
dropWhile( n -> n < 3, Stream.of( 0, 1, 2, 3, 0, 1, 2, 3, 4 ) )
.forEach( System.out::println );
3
0
1
2
3
4
这相当于 Scala dropWhile
.
That is the equivalent of Scala dropWhile
.
推荐答案
这种操作不是 Stream
的预期用例,因为它合并了元素之间的依赖关系.因此,该解决方案可能看起来不太优雅,因为您必须为谓词引入一个全状态变量:
This kind of operation is not an intended use case for Stream
s as it incorporates a dependency between the elements. Therefore the solution might not look elegant as you have to introduce a state-full variable for your predicate:
class MutableBoolean { boolean b; }
MutableBoolean inTail = new MutableBoolean();
IntStream.of(0, 1, 2, 3, 0, 1, 2, 3, 4)
.filter(i -> inTail.b || i >= 3 && (inTail.b = true))
.forEach(System.out::println);
请注意,与您的示例相比,条件必须颠倒.
Note that the condition had to be reversed compared to your example.
当然,你可以在方法中隐藏讨厌的细节:
Of course, you can hide the nasty details in a method:
public static void main(String... arg) {
dropWhile(n -> n < 3, Stream.of(0, 1, 2, 3, 0, 1, 2, 3, 4))
.forEach(System.out::println);
}
static <T> Stream<T> dropWhile(Predicate<T> p, Stream<T> s) {
class MutableBoolean { boolean b; }
MutableBoolean inTail = new MutableBoolean();
return s.filter(i -> inTail.b || !p.test(i) && (inTail.b = true));
}
<小时>
一种更复杂、但更简洁、可能更有效的方法是深入研究,即 Spliterator
接口:
static <T> Stream<T> dropWhile(Predicate<T> p, Stream<T> s) {
Spliterator<T> sp = s.spliterator();
return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(
sp.estimateSize(), sp.characteristics() & ~Spliterator.SIZED) {
boolean dropped;
public boolean tryAdvance(Consumer<? super T> action) {
if(dropped) return sp.tryAdvance(action);
do {} while(!dropped && sp.tryAdvance(t -> {
if(!p.test(t)) {
dropped=true;
action.accept(t);
}
}));
return dropped;
}
public void forEachRemaining(Consumer<? super T> action) {
while(!dropped) if(!tryAdvance(action)) return;
sp.forEachRemaining(action);
}
}, s.isParallel());
}
此方法的使用方式与第一个 dropWhile
方法相同,但它甚至可以与并行流一起使用,尽管效率不如您希望的那样.
this method can be used the same way as the first dropWhile
method, but it will work even with parallel streams, though not as efficient as you might wish.
这篇关于相当于 Scala dropWhile的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!