Как проверить, отсортирован ли Stream <T>?
С помощью Iterable<T>
легко:
T last = null;
for (T t : iterable) {
if (last != null && last.compareTo(t) > 0) {
return false;
}
last = t;
}
return true;
Но я не могу придумать простой способ сделать то же самое для Stream<T>
, который избегает потребления всех элементов, когда это не нужно.
Ответы
Ответ 1
Существует несколько методов для итерации по последовательным парам потока. Например, вы можете проверить этот вопрос. Конечно, моим любимым методом является использование библиотеки, которую я написал:
boolean unsorted = StreamEx.of(sourceStream)
.pairMap((a, b) -> a.compareTo(b) > 0)
.has(true);
Это короткое замыкание: оно будет закончено, как только оно обнаружит нарушение. Также он отлично работает с параллельными потоками.
Ответ 2
Вы можете захватить Stream spliterator и проверить, что он имеет SORTED-характеристику. Поскольку это операция с терминалом, вы не можете использовать Stream после (но вы можете создать еще один из этого разделителя, см. Также Преобразование Iterable в Stream с использованием Java 8 JDK).
Например:
Stream<Integer> st = Stream.of(1, 2, 3);
//false
boolean isSorted = st.spliterator().hasCharacteristics(Spliterator.SORTED);
Stream<Integer> st = Stream.of(1, 2, 3).sorted();
//true
boolean isSorted = st.spliterator().hasCharacteristics(Spliterator.SORTED);
В моем примере показано, что атрибут SORTED
появляется только в том случае, если вы получаете поток из источника, который сообщает атрибут SORTED
, или вы вызываете sorted()
в точке на конвейере.
Можно утверждать, что Stream.iterate(0, x -> x + 1);
создает поток SORTED
, но нет никакой информации о семантике функции, применяемой итеративно. То же самое относится к Stream.of(...)
.
Если конвейер бесконечен, то это единственный способ узнать. Если нет, и что разделитель не сообщает об этой характеристике, вам нужно будет пройти через элементы и посмотреть, не удовлетворяет ли она отсортированной характеристике, которую вы ищете.
Это то, что вы уже сделали с вашим подходом итератора, но затем вам нужно использовать некоторые элементы Stream (в худшем случае - все элементы). Вы можете сделать задачу параллелизуемой с некоторым дополнительным кодом, а затем вам решать, стоит ли это или нет...
Ответ 3
Вы можете использовать allMatch
с многострочной лямбдой, проверяя текущее значение по сравнению с предыдущим. Однако вам придется обернуть последнее значение в массив, поэтому лямбда может его изменить.
// infinite stream with one pair of unsorted numbers
IntStream s = IntStream.iterate(0, x -> x != 1000 ? x + 2 : x - 1);
// terminates as soon as the first unsorted pair is found
int[] last = {Integer.MIN_VALUE};
boolean sorted = s.allMatch(x -> {
boolean b = x >= last[0]; last[0] = x; return b;
});
В качестве альтернативы просто получите iterator
из потока и используйте простой цикл.
Ответ 4
Вы можете захватить операцию сокращения, чтобы сохранить последнее значение и сравнить его с текущим значением и выдать исключение, если оно не отсортировано:
.stream().reduce((last, curr) -> {
if (((Comparable)curr).compareTo(last) < 0) {
throw new Exception();
}
return curr;
});
EDIT: я разыграл другой пример ответа и заменил его своим кодом, чтобы показать его, только необходимое количество проверок.
http://ideone.com/ZMGnVW
Ответ 5
Наивное решение использует Итератор потока:
public static <T extends Comparable<T>> boolean isSorted(Stream<T> stream) {
Iterator<T> i = stream.iterator();
if(!i.hasNext()) return true;
T current = i.next();
while(i.hasNext()) {
T next = i.next();
if(current == null || current.compareTo(next) > 0) return false;
current = next;
}
return true;
}
Изменить: также можно было бы использовать spliterator для распараллеливания задачи, но выгоды были бы сомнительными, и увеличение сложности, вероятно, не стоит.
Ответ 6
Это последовательное, удерживающее состояние решение:
IntStream stream = IntStream.of(3, 3, 5, 6, 6, 9, 10);
final AtomicInteger max = new AtomicInteger(Integer.MIN_VALUE);
boolean sorted = stream.allMatch(n -> n >= max.getAndSet(n));
Параллелизация потребует введения диапазонов. Состояние, max
может быть рассмотрено в противном случае, но приведенное выше кажется самым простым.