javajava-8java-streamguava

How to transform a Java stream into a sliding window?


What is the recommended way to transform a stream into a sliding window?

For instance, in Ruby you could use each_cons:

irb(main):020:0> [1,2,3,4].each_cons(2) { |x| puts x.inspect }
[1, 2]
[2, 3]
[3, 4]
=> nil
irb(main):021:0> [1,2,3,4].each_cons(3) { |x| puts x.inspect }
[1, 2, 3]
[2, 3, 4]
=> nil

In Guava, I found only Iterators#partition, which is related but not a sliding window:

final Iterator<List<Integer>> partition =
   Iterators.partition(IntStream.range(1, 5).iterator(), 3);
partition.forEachRemaining(System.out::println);
-->
[1, 2, 3]
[4]

Solution

  • There's no such function in the API as it supports both sequential and parallel processing and it's really hard to provide an efficient parallel processing for sliding window function for arbitrary stream source (even efficient pairs parallel processing is quite hard, I implemented it, so I know).

    However if your source is the List with fast random access, you can use subList() method to get the desired behavior like this:

    public static <T> Stream<List<T>> sliding(List<T> list, int size) {
        if(size > list.size()) 
            return Stream.empty();
        return IntStream.range(0, list.size()-size+1)
                        .mapToObj(start -> list.subList(start, start+size));
    }
    

    Similar method is actually available in my StreamEx library: see StreamEx.ofSubLists().

    There are also some other third-party solutions which don't care about parallel processing and provide sliding functionality using some internal buffer. For example, protonpack StreamUtils.windowed.