使用Iterable<T>
,很容易:
T last = null;
for (T t : iterable) {
if (last != null && last.compareTo(t) > 0) {
return false;
}
last = t;
}
return true;
但我想不出一个干净的方法来为Stream<T>
做同样的事情,避免在不需要时消耗所有元素。
答案 0 :(得分:8)
有几种方法可以迭代连续的流对。例如,您可以查看this question。当然我最喜欢的方法是使用the library我写道:
boolean unsorted = StreamEx.of(sourceStream)
.pairMap((a, b) -> a.compareTo(b) > 0)
.has(true);
这是短路操作:一旦发现错误订单就会完成。它也适用于并行流。
答案 1 :(得分:3)
你可以抓住Stream的底层分裂器并检查它是否具有SORTED特性。由于它是终端操作,因此您无法使用Stream(但您可以从此分词器中创建另一个,请参阅Convert Iterable to Stream using 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的一些元素(在最坏的情况下,所有元素)。您可以使用一些额外的代码使任务可并行化,然后由您决定它是否值得...
答案 2 :(得分:3)
您可以劫持减少操作以保存最后一个值并将其与当前值进行比较,如果没有排序则抛出异常:
.stream().reduce((last, curr) -> {
if (((Comparable)curr).compareTo(last) < 0) {
throw new Exception();
}
return curr;
});
编辑:我分叉了另一个答案的例子,并用我的代码替换它,表明它只进行了必要的检查次数。
答案 3 :(得分:1)
您可以将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
并使用简单的循环。
答案 4 :(得分:1)
天真的解决方案使用流的迭代器:
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;
}
编辑:也可以使用分裂器来并行化任务,但增益会有问题,复杂性的增加可能不值得。
答案 5 :(得分:1)
这是一个顺序的州持股解决方案:
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
可能会以其他方式处理,但上述情况似乎最简单。
答案 6 :(得分:0)
我不知道它有多好,但是我有一个主意:
List<String> listOfStream
撰写了这篇文章: long countSorted = IntStream.range(1, listOfStream.size())
.map(
index -> {
if (listOfStream.get(index).compareTo(listOfStream.get(index-1)) > 0) {
return 0;
}
return index;
})
.sum();