与 Iterable<T>
, 这很容易:
T last = null;
for (T t : iterable) {
if (last != null && last.compareTo(t) > 0) {
return false;
}
last = t;
}
return true;
但我想不出一个干净的方法来做同样的事情 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>
避免在不必要时消耗所有元素。
有几种方法可以迭代连续的流对。例如,你可以检查 这个问题。当然我最喜欢的方法是使用 图书馆 我写了:
boolean unsorted = StreamEx.of(sourceStream)
.pairMap((a, b) -> a.compareTo(b) > 0)
.has(true);
这是短路操作:一旦发现错误,它就会完成。它也适用于并行流。
你可以抓住Stream的底层分裂器并检查它是否具有SORTED特性。由于它是一个终端操作,你不能在之后使用Stream(但是你可以从这个spliterator创建另一个,参见 使用Java 8 JDK将Iterable转换为Stream)。
例如:
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的一些元素(在最坏的情况下,所有元素)。您可以使用一些额外的代码使任务可并行化,然后由您决定它是否值得...
您可以劫持减少操作以保存最后一个值并将其与当前值进行比较,如果未排序则抛出异常:
.stream().reduce((last, curr) -> {
if (((Comparable)curr).compareTo(last) < 0) {
throw new Exception();
}
return curr;
});
编辑:我分叉了另一个答案的例子,并用我的代码替换它,以显示它只进行必要数量的检查。
你可以用 allMatch
使用多行lambda,检查当前值与前一个值。但是,您必须将最后一个值包装到数组中,因此lambda可以对其进行修改。
// 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
从流中使用一个简单的循环。
一个天真的解决方案使用流的迭代器:
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;
}
编辑:也可以使用分裂器来并行化任务,但增益会有问题,复杂性的增加可能不值得。
这是一个顺序的状态持有解决方案:
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
可能会以其他方式处理,但上述内容似乎最简单。