什么是迭代Java 8 Stream的最好方法,这样我就可以为每个元素(forEach)执行一个函数,而为每10个元素执行另一个函数。使用foreach的每个元素都显示在下面。我可以使用什么函数来截取eveyr nth元素并执行第二个函数调用?
以下示例代码: -
Stream<String> strings = Files.lines(path); //some stream
stream.forEach(s -> System::println)// every element but how can i perform
答案 0 :(得分:5)
从Guava version 22开始,您可以使用Streams.forEachPair
来完成您想要的任务:
Stream<String> strings = Stream.of("a", "b", "c", "d", "e", "f");
Stream<Long> indexes = Stream.iterate(0L, i -> i + 1L);
Streams.forEachPair(strings, indexes, (s, i) -> {
if (i % 3 == 0) {
System.out.println("Every 3rd element: " + s);
} else {
System.out.println(s);
}
});
这会从Long
开始创建无限的连续0L
元素流,并在内部使用strings
流压缩此流。 Streams.forEachPair
接受BiConsumer
接收每对元素,每个元素一个,并根据索引是否为第3个元素执行操作。
您可以使用以下辅助方法对此进行更多抽象:
static <T> void forEachNthOrElse(
Stream<T> stream,
int n,
Consumer<T> onNthElement,
Consumer<T> onAnyOther) {
Streams.forEachPair(
stream,
Stream.iterate(0L, i -> i + 1),
(t, i) -> {
Consumer<T> action = i % n == 0 ? onNthElement : onAnyOther;
action.accept(t);
});
}
并且,对于同一个示例,您可以按如下方式使用它:
forEachNthOrElse(
strings,
3,
s -> System.out.println("Every 3rd element: " + s),
System.out::println);
注意:我不确定您是否需要始终执行System.out::println
操作,或仅在元素不是第n个元素时执行。我实现了BiConsumer
来执行一个动作或另一个动作。如果不是这种情况(即如果你想为第n个元素执行一个动作并且总是执行另一个动作,即使对于第n个元素),你应该相应地改变代码。
答案 1 :(得分:2)
使用Vavr(Javaslang),使用提供的zipWithIndex
方法可以相当容易:
stream
.zipWithIndex()
.forEach(t2 -> {
// something that runs for each element
if (t2._2 % 10 == 0) {
// something that runs every 10 elements
}
});
答案 2 :(得分:1)
由于流不支持chunk
/ split
功能,但我已在其他问题中回答,因此我将其粘贴到此处。我希望它可以帮助你,例如:
Stream<String> strings = Files.lines(path); //some stream
// v--- skip the last chunk if the chunk size < 10?
split(strings, 10 , true).forEach((List<String> chunk)->{
// each chunk size is 10 ---^
// v--- Every element using foreach displayed
chunk.forEach(System.out::println);
// v--- another for every 10 element.
System.out.println(chunk);
});
import java.util.ArrayList;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.stream.Stream;
import static java.util.stream.StreamSupport.stream;
<T> Stream<List<T>> split(Stream<T> source,
int limit, boolean skipRemainingElements) {
//variables just for printing purpose
Spliterator<T> it = source.spliterator();
long size = it.estimateSize();
int c = it.characteristics();// characteristics
return stream(new AbstractSpliterator<List<T>>(size, c) {
private int thresholds = skipRemainingElements ? limit : 1;
@Override
@SuppressWarnings("StatementWithEmptyBody")
public boolean tryAdvance(Consumer<? super List<T>> action) {
List<T> each = new ArrayList<>(limit);
while (each.size() < limit && it.tryAdvance(each::add)) ;
if (each.size() < thresholds) return false;
action.accept(each);
return true;
}
}, false).onClose(source::close);
}
答案 3 :(得分:1)
您也可以尝试自己编写有状态方法,而无需使用任何第三方库,它可能看起来像这样:
foreachAndEveryNthDoSpecial(myStream, t -> yourAction, 10, t -> specialAction);
然后可以这样调用:
options.isdedicated = "<?php echo $isdedicated;?>" == 'true' ? true : false;