javajava-stream

java streams: easiest way to find adjacent value match


How would it be possible to convert this iterative block of code to streams?

Integer prev = -1;
boolean adjacentPair = false;

for(Integer num : numberList) {
    if (num.equals(prev)) {
        adjacentNumberSame = true;
        break;
    }
    prev = num;
}
return adjacentNumberSame 

Solution

  • This is one (not so great) way to do it:

    IntStream.range(1, numberList.size())
             .anyMatch(i -> numberList.get(i).equals(numberList.get(i-1)));
    

    If your numberList is an ArrayList or something similar its complexity is acceptable. If not, you'd better use iterator. Like so:

    var Iter = list.stream().iterator();
    var res = list.stream()
                  .skip(1)
                  .map(v -> v.equals(Iter.next()) )
                  .anyMatch(v -> v)
                  ;
    

    More elegant ways require some third-party libraries with a zip function. With zip it can look like:

    var res = zip(
                  list.stream().skip(1),
                  list.stream(),
                  (a, b) -> a.equals(b)
              ).anyMatch(x->x);
    

    Or you can write your own zip. Something like this:

    public static <A,B,C> Stream<C> zip(Stream<A> listA, Stream<B> listB, BiFunction<A,B,C> zipper){
        var iB = listB.iterator();
        return listA.filter( a -> iB.hasNext())
                    .map( a -> zipper.apply(a, iB.next()) );
    }
    

    PS. I would not recommend reduce as it used in @vbezhenar's answer. Because it will not shortcircuit, as you can see here https://repl.it/repls/DisastrousWideRevisioncontrol (look for exception)