EDIT - Nov 28, 2017
As user @Emiel suggests in the comments, the best way to do this would be to use Stream.itearate
to drive the list through a sequence of indices:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int skip = 3;
int size = list.size();
// Limit to carefully avoid IndexOutOfBoundsException
int limit = size / skip + Math.min(size % skip, 1);
List<Integer> result = Stream.iterate(0, i -> i + skip)
.limit(limit)
.map(list::get)
.collect(Collectors.toList());
System.out.println(result); // [1, 4, 7, 10]
This approach doesn't have the drawbacks of my previous answer, which comes below (I've decided to keep it for historical reasons).
Another approach would be to use Stream.iterate()
the following way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int skip = 3;
int size = list.size();
// Limit to carefully avoid IndexOutOfBoundsException
int limit = size / skip + Math.min(size % skip, 1);
List<Integer> result = Stream.iterate(list, l -> l.subList(skip, l.size()))
.limit(limit)
.map(l -> l.get(0))
.collect(Collectors.toList());
System.out.println(result); // [1, 4, 7, 10]
The idea is to create a stream of sublists, each one skipping the first N
elements of the previous one (N=3
in the example).
We have to limit the number of iterations so that we don't try to get a sublist whose bounds are out of range.
Then, we map our sublists to their first element and collect our results. Keeping the first element of every sublist works as expected because every sublist's begin index is shifted N
elements to the right, according to the source list.
This is also efficient, because the List.sublist()
method returns a view of the original list, meaning that it doesn't create a new List
for each iteration.
EDIT: After a while, I've learnt that it's much better to take either one of @sprinter's approachs, since subList()
creates a wrapper around the original list. This means that the second list of the stream would be a wrapper of the first list, the third list of the stream would be a wrapper of the second list (which is already a wrapper!), and so on...
While this might work for small to medium-sized lists, it should be noted that for a very large source list, many wrappers would be created. And this might end up being expensive, or even generating a StackOverflowError
.