I want to take a stream of strings and turn it into a stream of word pairs. eg:
I have: { \"A\", \"Apple\", \"B\", \"Banana\", \"C\", \"Carrot\" }
If you:
Then you can create a method to group elements from a stream using Java 8 low-level stream builders StreamSupport and Spliterator:
class StreamUtils {
public static Stream> sliding(int size, Stream stream) {
return sliding(size, 1, stream);
}
public static Stream> sliding(int size, int step, Stream stream) {
Spliterator spliterator = stream.spliterator();
long estimateSize;
if (!spliterator.hasCharacteristics(Spliterator.SIZED)) {
estimateSize = Long.MAX_VALUE;
} else if (size > spliterator.estimateSize()) {
estimateSize = 0;
} else {
estimateSize = (spliterator.estimateSize() - size) / step + 1;
}
return StreamSupport.stream(
new Spliterators.AbstractSpliterator>(estimateSize, spliterator.characteristics()) {
List buffer = new ArrayList<>(size);
@Override
public boolean tryAdvance(Consumer super List> consumer) {
while (buffer.size() < size && spliterator.tryAdvance(buffer::add)) {
// Nothing to do
}
if (buffer.size() == size) {
List keep = new ArrayList<>(buffer.subList(step, size));
consumer.accept(buffer);
buffer = keep;
return true;
}
return false;
}
}, stream.isParallel());
}
}
Methods and parameters naming was inspired in their Scala counterparts.
Let's test it:
Stream testing = Stream.of("A", "Apple", "B", "Banana", "C", "Carrot");
System.out.println(StreamUtils.sliding(2, testing).collect(Collectors.toList()));
[[A, Apple], [Apple, B], [B, Banana], [Banana, C], [C, Carrot]]
What about not repeating elements:
Stream testing = Stream.of("A", "Apple", "B", "Banana", "C", "Carrot");
System.out.println(StreamUtils.sliding(2, 2, testing).collect(Collectors.toList()));
[[A, Apple], [B, Banana], [C, Carrot]]
And now with an infinite Stream
:
StreamUtils.sliding(5, Stream.iterate(0, n -> n + 1))
.limit(5)
.forEach(System.out::println);
[0, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]
[3, 4, 5, 6, 7]
[4, 5, 6, 7, 8]