Reputation: 1508
I am learning and new to Java 8 Stream API,
I wanted to write a program to find even numbers in integer array using IntStream
, so I came up with this solution,
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
IntStream.of(numbers).filter(i -> i%2 == 0).forEach(System.out::println);
and this is working correctly for me.
but how can I modify the filter
to skip certain array indexes from being checked from numbers
?
for example,
if i want to skip numbers[1]
from being checked if it even or not then what should i do ?
because i
in the filter are the values of the array elements not their indexes.
is it possible to do so ?
Upvotes: 6
Views: 6017
Reputation: 2114
As an alternative solution, you can achieve the same result using iterators.
I'm the author of Enumerables which wraps iterable collections with functionality familiar from Stream. It provides a filter method that has an index parameter.
int[] numbers = {1,2,3,4,5,6,7,8,9,10};
IntStream stream = IntStream.of(numbers);
Enumerable<Integer> enumerable = new Enumerable(() -> stream.iterator());
Enumerable<Integer> evens = enumerable.filter((x, i) -> x % 2 == 0 && i != 1);
return evens.toList().stream();
Upvotes: 2
Reputation: 4579
A variant of @James_D's answer.
Imagine if we could avoid the usage of situational classes such as IndexedValue, because we are silly billies or something.
Well, imagine no more:
int[] numbers = ... ;
IntStream.range(0, numbers.length)
// an anonymous class is defined at this juncture
// for the sake of discussion, said class is named
// Whatever (FF8 reference).
.mapToObj(i -> new Object() {
final int index = i;
final int value = numbers[i];
})
// IntStream translated to Stream<Whatever>
.filter(v -> v.index != 1)
// Stream<Whatever> with non-1 indices
.filter(v -> v.value % 2 == 0)
// Stream<Whatever> with even values
.mapToInt(v -> v.value)
// Stream<Whatever> to IntStream
.forEach(System.out::println)
;
Disclaimer: I know this because I got bored once and tried it myself. There is no guarantee that this code will work with non-JavaC compilers. (Apparently, Eclipse's type inference is not as sexy as javac's. Whatever. [FF8 reference])
Upvotes: 3
Reputation: 209653
Create a stream of the array indices instead, and filter it, before mapping to the array elements:
int[] numbers = ...;
IntStream.range(0, numbers.length).filter(i -> i!=1)
.map(i -> numbers[i]).forEach(System.out::println);
If you need first to filter some elements out by index, and some out by value, you can have one filter before the map and one after.
If you need to check both the index and the value in the same filter, then I think the best way is to create a class to hold both values:
class IndexedValue {
private int index, value;
IndexedValue(int index, int value) {
this.index = index ;
this.value = value ;
}
int getIndex() { return index ;}
int getValue() { return value ;}
}
and then you can do
int[] numbers = ... ;
IntStream.range(0, numbers.length).map(i -> new IndexedValue(i, numbers[i]))
.filter(v -> v.getIndex() == 1 || v.getValue() % 2 == 0)
.forEach(System.out::println);
Upvotes: 10