bhupen
bhupen

Reputation: 470

Java 8 Stream: How to compare current element with next element?

How to get the next element from a List using Java 8 Streams?

If I am iterating over a List, I want to compare current with next element of the list.

Is it doable using Java 8 Stream?

Upvotes: 33

Views: 49828

Answers (6)

Georg Moser
Georg Moser

Reputation: 716

If you had a list of Integers for example and wanted to check if they are sorted ascending, you could do as follows:

@Test
public void test_listIsSorted() {

    // create integer list for testing purposes: 0,1,2,3, .., 10
    List<Integer> integerList = IntStream.range(0, 10)
            .boxed()
            .collect(Collectors.toList());

    // stream list and compare item n with n+1
    integerList.stream()
            .reduce((integer1, integer2) -> {
                assert integer1 < integer2 : "ordering must be ascending";
                // return second value (which will be processed as "integer1" in the next iteration
                return integer2;
            });

}

This will compare pairs like: (0,1),(1,2),...

Upvotes: 2

Beezer
Beezer

Reputation: 1108

I had to do the same and compare the differences of the elements of a stream (originally an array). So I used a method as a parameter to the UnaryOperator that .map() expects as follows...and it worked for me without any special gizmo's:

import java.util.Arrays;

class streamDiffUtil {
    public static void main(String[] args) {
        int[] elements = {1,2,5};
        int result = Arrays.stream(elements)
                .map(value -> calcMaxDiff(value, elements))
                .max()
                .getAsInt();
        System.out.println(result);
    }

    private static int calcMaxDiff(int j, int[] elements) {
        return Arrays.stream(elements)
                .map(value -> Math.abs(j-value))
                .max().getAsInt();
    }
}

What would be nice is to know how the method calcMaxDiff equates to a UnaryIntOperator in the .map signature. That is a little beyond me. Hope this helps you.

Upvotes: 0

Marc Dzaebel
Marc Dzaebel

Reputation: 435

Stream.reduce could be used, depending on the goal. As you said, you'd like to compare consecutive elements, the following would print "Same 3":

Stream.of(1,2,3,3).reduce((a,b)->{
    if(a==b) System.out.println("Same "+a);
    return b; // will be "a" for next reduction
});

Upvotes: 9

walkeros
walkeros

Reputation: 4942

You always do one of following:

  1. Convert your stream to a stream of elements containing "history" of last few elements of the stream
  2. Process your stream in such a way that currently processed element is considered to be "next" element and previously processed element is considered to be "current" element.

Implementations of both solutions can be seen in this thread: Is it possible to get next element in the Stream?

Upvotes: 0

Tagir Valeev
Tagir Valeev

Reputation: 100339

My free StreamEx library allows you to process the pairs of the stream elements using additional pairMap intermediate operation. Like this:

StreamEx.of(input).pairMap((current, next) -> doSomethingWith(current, next));

Where input is a Collection, array or Stream. For example, this way you can easily check whether input is sorted:

boolean isSorted = StreamEx.of(input)
                           .pairMap((current, next) -> next.compareTo(current))
                           .allMatch(cmp -> cmp >= 0);

There's also forPairs terminal operation which is a forEach analog to all pairs of input elements:

StreamEx.of(input).forPairs((current, next) -> doSomethingWith(current, next));

These features work nicely with any stream source (either random access or not) and fully support the parallel streams.

Upvotes: 17

Eran
Eran

Reputation: 394156

One way is to generate an IntStream of the indices, and fetch the List elements by their index. This is only efficient if the List supports random access (i.e. if your List is a LinkedList, it would be a bad idea, since list.get(i) doesn't take constant time).

For example :

IntStream.range(0,list.size()-1).forEach(i -> {
    doSomething(list.get(i),list.get(i+1));
});

Another way is to store the last element in an array :

List<Element> list = ...
Element[] arr = new Element[1];
list.stream().forEach(e -> {
    if (arr[0] != null)
        doSomething(arr[0],e); 
    arr[0]=e;
});

This will only work for sequential streams.

Upvotes: 14

Related Questions