相当于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
的预期用例,因为它包含了元素之间的依赖关系。因此,解决方案可能看起来不太优雅,因为您必须为谓词引入一个state-full变量:
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屋!