Suppose I have this list:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

Can I use the Java Stream API to transfer every second element from this list to get such a list?

 [1, 3, 5, 7, 9] 

Or maybe every third element?

 [1, 4, 7, 10] 

In fact, I am looking for such a function to take every nth element from the stream:

 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List<Integer> list2 = list.stream().takenth(3).collect(Collectors.toList()); System.out.println(list2); // => [1, 4, 7, 10] 

1 answer 1

One of the main reasons for introducing Java threads was to allow concurrent operations. This led to the requirement that Java Streams operations, such as map and filter , do not depend on the position of the element in the stream or the elements around it. This has the advantage of making it easy to separate threads for parallel processing. The disadvantage is the complexity of some operations.

Thus, there is no easy way to do something, for example, to take every nth item or compare each item to the sum of all previous items.

The easiest way to fulfill your requirement is to use a list index:

 List<String> list = ...; return IntStream.range(0, list.size()) .filter(n -> n % 3 == 0) //3 - каждый 3-ий элемент .mapToObj(list::get) .collect(Collectors.toList()); 

Note from Sergey Gornostaev :

The solution is working, but I must say, such a use of streams is an anti-pattern. It is not advisable to work with data outside the stream. As soon as the idea of ​​accessing a variable comes up, you should be on your guard and think, "Am I using the streams incorrectly or are the streams not suitable here at all?"


Using Stream.iterate

 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] 

Using the Guava ( GitHub ) library:

 Streams .mapWithIndex(stream, SimpleImmutableEntry::new) .filter(entry -> entry.getValue() % 3 == 0) .map(Entry::getKey) .collect(Collectors.toList()); 

Using the AbacusUtil library:

 Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) .filter(MutableInt.of(0), (e, idx) -> idx.getAndDecrement() % 3 == 0) .println(); 

Using the jOOλ library and its zipWithIndex() method:

 System.out.println( Seq.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) .zipWithIndex() // This produces a Tuple2(yourvalue, index) .filter(t -> t.v2 % 3 == 0) // Filter by the index .map(t -> t.v1) // Remove the index again .toList() );