1

I have a list of objects a List<B> structure as follows:

class B {
    int x;
    String y;
}

Now I want to find last occurrence of a B object b such that b.x=1. I can do that by simply running a for loop and updating index for each match. But how to do that in Java 8 I am not getting.

I saw there are Java 8 APIs for findFirst() and findAny(), but did not find anything similar for finding last occurrence.

Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
Joy
  • 4,197
  • 14
  • 61
  • 131
  • The dupe looks good, but this question seems to ask for the index of the last match. @OP Do you actually need the index or just the last matching element? – Jorn Vernee Jul 17 '18 at 12:49

5 Answers5

2
 Optional<B> reduce = list.stream()
            .filter(b -> b.x == 1)
            .reduce((a, b) -> b);

This will take identical objects( having the same value x) and return the next one of them in list.

aleshka-batman
  • 187
  • 1
  • 13
2

Using the reduce operation you can achieve it, you start by keeping the element that matches, then for each pair (ordered) keep the second until there is one left and return it

static B getLastBeFromInt(List<B> list, int i){
    return list.stream().filter(b -> b.x==i).reduce((first,second) -> second).orElse(null);
}

azro
  • 53,056
  • 7
  • 34
  • 70
  • 2
    better to return `Optional` and let the user of this method decide what to do in the "no value" case. – Ousmane D. Jul 17 '18 at 13:22
  • @Aominè the "user" is the one who will use this code, he’ll see what he want to do – azro Jul 17 '18 at 13:29
  • Not every user of an API can modify the code in use. I am not talking about the author of the code. Anyway, you're suggesting to return `null` in the no value case which is not leveraging the `Optional` type as much as possible. The main reason for Optional to exist was to help prevent NullPointerException and your code uses Optional but doesn't help prevent that. – Ousmane D. Jul 17 '18 at 13:51
1

Just like with loop based searches, when you are looking for the last occurence of something, the most efficient solution is to search backwards. Further, if you need to find an index with the Stream API, you have to stream over the indices in the first place:

OptionalInt pos = IntStream.rangeClosed(1-list.size(), 0).map(i -> -i)
    .filter(ix -> list.get(ix).x == 1)
    .findFirst();

pos.ifPresent(ix -> System.out.println("found "+list.get(ix)+" at "+ix));
Holger
  • 285,553
  • 42
  • 434
  • 765
0

Another idea would be running your Stream from the last to the first index and use Stream::findFirst.

Optional<B> lastElement = IntStream.range(0, bs.size())
                                   .mapToObj(i -> bs.get(bs.size() - 1 - i))
                                   .filter(b -> b.x == 1).findFirst();
Flown
  • 11,480
  • 3
  • 45
  • 62
0

Java-9 version of finding the index of the last occurence satisfying the provided criteria in filter:

IntStream.iterate(list.size()-1, i -> i >= 0, i -> i - 1)
         .filter(i -> list.get(i).x == 1)
         .findFirst()
         .ifPresent(i -> System.out.println("found "+list.get(i)+" at "+i));
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126