Joe
Joe

Reputation: 1508

How to skip particular array index when using IntStream.filter in Java 8

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

Answers (3)

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

srborlongan
srborlongan

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

James_D
James_D

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

Related Questions