Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import java.util.Arrays;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class PairMapSample {
static <T, R> Stream<R> pairMap(Stream<T> input, BiFunction<T, T, R> mapper) {
return StreamSupport.stream(new PairMapSpliterator<>(input.spliterator(), mapper), input.isParallel())
.onClose(input::close);
}
static class PairMapSpliterator<T, R> extends Spliterators.AbstractSpliterator<R> {
private final Spliterator<T> spliterator;
private final BiFunction<T, T, R> mapper;
private T prev;
private boolean hasPrevious;
PairMapSpliterator(Spliterator<T> spliterator, BiFunction<T, T, R> mapper) {
super(calcSize(spliterator), spliterator.characteristics() & (SIZED | ORDERED));
this.spliterator = spliterator;
this.mapper = mapper;
}
@Override
public boolean tryAdvance(Consumer<? super R> action) {
if (!hasPrevious) {
if (!spliterator.tryAdvance(first -> prev = first)) {
return false;
}
hasPrevious = true;
}
return spliterator.tryAdvance(next -> action.accept(mapper.apply(prev, prev = next)));
}
private static long calcSize(Spliterator<?> spliterator) {
long size = spliterator.estimateSize();
return size <= 0 ? 0 : size == Long.MAX_VALUE ? Long.MAX_VALUE : size - 1;
}
@Override
public void forEachRemaining(Consumer<? super R> action) {
spliterator.forEachRemaining(next -> {
if (!hasPrevious) {
hasPrevious = true;
} else {
action.accept(mapper.apply(prev, next));
}
prev = next;
});
}
}
public static void main(String[] args) {
List<String> input = Arrays.asList("lion", "fox", "hare", "carrot");
pairMap(input.stream(), (a, b) -> a + " eats " + b).forEach(System.out::println);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment