Java 8 Stream: Как сравнить текущий элемент со следующим элементом?

Как получить следующий элемент из List используя потоки Java 8?

Если я перебираю List, я хочу сравнить текущий со следующим элементом списка.

Это выполнимо с использованием Java 8 Stream?

Ответ 1

Моя бесплатная библиотека StreamEx позволяет обрабатывать пары элементов потока с помощью дополнительных pairMap промежуточная операция. Вот так:

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

Где input - это Collection, массив или Stream. Например, таким образом вы можете легко проверить, отсортирован ли вход:

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

Также существует операция forPairs, которая является аналогом forEach для всех пар входных элементов:

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

Эти функции прекрасно работают с любым источником потока (либо произвольным доступом, либо нет), и полностью поддерживают параллельные потоки.

Ответ 2

Один из способов - создать индекс IntStream для индексов и получить элементы List по их индексу. Это эффективно, только если List поддерживает произвольный доступ (т.е. Если ваш List является LinkedList, это будет плохая идея, так как list.get(i) не принимает постоянного времени).

Например:

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

Другой способ - сохранить последний элемент в массиве:

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

Это будет работать только для последовательных потоков.

Ответ 3

Вы всегда выполняете одно из следующих действий:

  • Преобразуйте поток в поток элементов, содержащих "историю" последних нескольких элементов потока.
  • Обработать поток таким образом, чтобы текущий обработанный элемент считался "следующим", а ранее обработанный элемент считается "текущим" элементом.

Реализации обоих решений можно увидеть в этой теме: Можно ли получить следующий элемент в потоке?

Ответ 4

Мне пришлось сделать то же самое и сравнить различия элементов потока (первоначально массив). Поэтому я использовал метод в качестве параметра для UnaryOperator, который .map() ожидает следующим образом... и он работал для меня без каких-либо специальных штуковин:

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();
    }
}

Было бы неплохо узнать, как метод calcMaxDiff приравнивается к UnaryIntOperator в сигнатуре .map. Это немного за мной. Надеюсь, это поможет вам.

Ответ 5

Stream.reduce может быть использован, в зависимости от цели. Как вы сказали, вы хотите сравнить последовательные элементы, следующее выдает "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
});