J'ai mis en place un spliterator wrapper qui prend chaque n
éléments T
de l'original spliterator et produit List<T>
:
public class ConsecutiveSpliterator<T> implements Spliterator<List<T>> {
private final Spliterator<T> wrappedSpliterator;
private final int n;
private final Deque<T> deque;
private final Consumer<T> dequeConsumer;
public ConsecutiveSpliterator(Spliterator<T> wrappedSpliterator, int n) {
this.wrappedSpliterator = wrappedSpliterator;
this.n = n;
this.deque = new LinkedList<>();
this.dequeConsumer = new Consumer<T>() {
@Override
public void accept(T t) {
deque.addLast(t);
}
};
}
@Override
public boolean tryAdvance(Consumer<? super List<T>> action) {
deque.pollFirst();
fillDeque();
if (deque.size() == n) {
List<T> list = new ArrayList<>(deque);
action.accept(list);
return true;
} else {
return false;
}
}
private void fillDeque() {
while (deque.size() < n && wrappedSpliterator.tryAdvance(dequeConsumer))
;
}
@Override
public Spliterator<List<T>> trySplit() {
return null;
}
@Override
public long estimateSize() {
return wrappedSpliterator.estimateSize();
}
@Override
public int characteristics() {
return wrappedSpliterator.characteristics();
}
}
Méthode suivante peut être utilisée pour créer un consécutives de flux:
public <E> Stream<List<E>> consecutiveStream(Stream<E> stream, int n) {
Spliterator<E> spliterator = stream.spliterator();
Spliterator<List<E>> wrapper = new ConsecutiveSpliterator<>(spliterator, n);
return StreamSupport.stream(wrapper, false);
}
Exemple d'utilisation:
consecutiveStream(Stream.of(0, 1, 2, 3, 4, 5), 2).map(
new Function<List<Integer>, Pair>() {
public Pair apply(List<Integer> list) {
return new Pair(list.get(0), list.get(1));
}
}).forEach(System.out::println);