Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find value n steps away from target in List with stream

Suppose I have a simple list:

List<String> listOne = Arrays.asList("str1", "result1", "test", "str4", "result2", "test", "str7", "str8");

The target is "test" and I want to add the value before the target into a new list, so the output would be [result1, result2].

It's easy enough to add the "test" values with something like listTwo = listOne.stream().filter(i -> i.equals("test")).collect(Collectors.toList()); but how can I get the values elsewhere based on the location of the target ( in my example it's just the element before the target )

I tried just changing the i to i - 1 but that did nothing.

I am aware I can do it with a simple for loop, but just wondering how to apply the same logic with a stream.

for (int i = 1; i < listOne.size(); i++) {
    if (listOne.get(i).equals("test")) {
        listTwo.add(listOne.get(i - 1));
    }
}
like image 384
achAmháin Avatar asked Jan 31 '19 15:01

achAmháin


2 Answers

To build on top of Naman's answer:

  • You can directly collect to a List<String>, which is more functional.
  • Also I would do the .equals test the other way in case one of the element of the list is null

Here you go:

List<String> listTwo = IntStream.range(1, listOne.size())
    .filter(i -> "test".equals(listOne.get(i))) // stream of indexes of "test" elements
    .mapToObj(i -> listOne.get(i-1))            // stream of elements at the index below
    .collect(Collectors.toList());
like image 67
Bentaye Avatar answered Oct 21 '22 07:10

Bentaye


Something like

    IntStream.range(1, listOne.size())
            .filter(i -> listOne.get(i).equals("test"))
            .mapToObj(i -> listOne.get(i - 1))
            .forEach(item -> listTwo.add(item));
like image 26
Naman Avatar answered Oct 21 '22 09:10

Naman