我想要一个方法,List<T>
T
实现Comparable
并返回true
或false
,具体取决于列表是否已排序
在Java中实现此功能的最佳方法是什么?显而易见的是,泛型和通配符意味着能够轻松处理这些事情,但我总是纠缠不清。
使用类似方法检查列表是否按相反顺序也是很好的。
答案 0 :(得分:99)
Guava通过其令人敬畏的Ordering类提供此功能。 Ordering
是Comparator
++。在这种情况下,如果您有一个实现Comparable
的某种类型的列表,您可以写:
boolean sorted = Ordering.natural().isOrdered(list);
这适用于任何Iterable
,而不仅仅是List
,您可以轻松处理null
,方法是指定它们应该在其他非null
之前或之后出现元素:
Ordering.natural().nullsLast().isOrdered(list);
此外,由于您提到您希望能够检查逆序和正常,因此可以这样做:
Ordering.natural().reverse().isOrdered(list);
Java 8用户:改为使用等效的Comparators#isInOrder(Iterable)
,因为其余的Ordering大部分都已过时(如课程documentation中所述)。
答案 1 :(得分:25)
这是一个通用方法,可以解决这个问题:
public static <T extends Comparable<? super T>>
boolean isSorted(Iterable<T> iterable) {
Iterator<T> iter = iterable.iterator();
if (!iter.hasNext()) {
return true;
}
T t = iter.next();
while (iter.hasNext()) {
T t2 = iter.next();
if (t.compareTo(t2) > 0) {
return false;
}
t = t2;
}
return true;
}
答案 2 :(得分:16)
易:
List tmp = new ArrayList(myList);
Collections.sort(tmp);
boolean sorted = tmp.equals(myList);
或(如果元素具有可比性):
Object prev;
for( Object elem : myList ) {
if( prev != null && prev.compareTo(elem) > 0 ) {
return false;
}
prev = elem;
}
return true;
或(如果元素不具有可比性):
Object prev;
for( Object elem : myList ) {
if( prev != null && myComparator.compare(prev,elem) > 0 ) {
return false;
}
prev = elem;
}
return true;
包含空值的列表的实现失败。在这种情况下,您必须添加适当的检查。
答案 3 :(得分:11)
如果您使用的是Java 8,则流可能会有所帮助。
list.stream().sorted().collect(Collectors.toList()).equals(list);
此代码将对列表进行排序,并将其元素收集到另一个列表中,然后将其与初始列表进行比较。如果两个列表在相同位置包含相同的元素,则比较将成功。
此方法可能不是性能最快的解决方案,但它是最容易实现的方法,不涉及第三方框架。
答案 4 :(得分:5)
检查列表或任何数据结构是否只需要O(n)时间。只需使用Iterator
接口遍历列表并从头到尾运行数据(在您的情况下,您已经准备好它作为可比较类型),您可以找到它是否已排序
答案 5 :(得分:3)
只需使用迭代器查看List<T>
。
public static <T extends Comparable> boolean isSorted(List<T> listOfT) {
T previous = null;
for (T t: listOfT) {
if (previous != null && t.compareTo(previous) < 0) return false;
previous = t;
}
return true;
}
答案 6 :(得分:2)
这就是我要做的事情:
public static <T extends Comparable<? super T>> boolean isSorted(List<T> list) {
if (list.size() != 0) {
ListIterator<T> it = list.listIterator();
for (T item = it.next(); it.hasNext(); item = it.next()) {
if (it.hasPrevious() && it.previous().compareTo(it.next()) > 0) {
return false;
}
}
}
return true;
}
答案 7 :(得分:2)
private static <T extends Comparable<? super T>> boolean isSorted(List<T> array){
for (int i = 0; i < array.size()-1; i++) {
if(array.get(i).compareTo(array.get(i+1))> 0){
return false;
}
}
return true;
}
zzzzz不确定你们这些人在做什么,但这可以通过简单的循环来完成。
答案 8 :(得分:2)
如果您需要进行单元测试,可以使用AssertJ。它包含一个断言,用于检查List是否已排序:
isSortedAccordingTo
还有一种替代方法{{1}},如果您想使用自定义比较器进行排序,它会使用比较器。
答案 9 :(得分:1)
这是一个需要O(n)时间(最坏情况)的操作。您将需要处理两种情况:列表按降序排序,列表按升序排序。
您需要将每个元素与下一个元素进行比较,同时确保保留订单。
答案 10 :(得分:0)
数组上的一个简单实现:
public static <T extends Comparable<? super T>> boolean isSorted(T[] a, int start, int end) {
while (start<end) {
if (a[start].compareTo(a[start+1])>0) return false;
start++;
}
return true;
}
转换列表:
public static <T extends Comparable<? super T>> boolean isSorted(List<T> a) {
int length=a.size();
if (length<=1) return true;
int i=1;
T previous=a.get(0);
while (i<length) {
T current=a.get(i++);
if (previous.compareTo(current)>0) return false;
previous=current;
}
return true;
}
答案 11 :(得分:0)
这是使用Iterable
和Comparator
的方法。
<T> boolean isSorted(Iterable<? extends T> iterable,
Comparator<? super T> comparator) {
T previous = null;
for (final T current : iterable) {
if (previous != null && comparator.compare(previous, current) > 0) {
return false;
}
previous = current;
}
return true;
}
还有Iterable
中的Comparable
的方法和用于排序的标志。
<T extends Comparable<? super T>> boolean isSorted(
Iterable<? extends T> iterable, boolean natural) {
return isSorted(iterable, natural ? naturalOrder() : reverseOrder());
}
答案 12 :(得分:0)
使用Java 8流:
boolean isSorted = IntStream.range(1, list.size())
.map(index -> list.get(index - 1).compareTo(list.get(index)))
.allMatch(order -> order <= 0);
这也适用于空列表。但是,它仅对于还实现RandomAccess
标记界面(例如ArrayList
)的列表有效。
答案 13 :(得分:0)
IMO,从我所看到的,检查这个的复杂性和第二次执行排序一样糟糕,我知道如果没有排序,人们会短路返回,但如果列表实际上是排序,然后整个长度将被遍历...,我认为只是让代码继续,就像列表被排序一样,让代码本身确定它是否是。
我建议放置一个错误,详细说明为什么会失败的特定行会这样做,因为它的集合没有反转/排序等...
例如
行 detachTailIndex.run()
将给出 NullPointerException(),
if (fromReversedMethod && detachTailIndex == null) {
throw new NullPointerException("detachTailIndex was null. \n
Reason: The List<> is required to be reversed before submission")
}
或者,如果您的计划是在排序时使用条件,则您可以使用 null 来验证它是否已排序并选择其他选项。
如果没有其他选项,则使用其他响应即可。
这是另一个例子:
int key = entry.getKey();
List<Integer> shouldBeReversed = entry.getValue();
try {
//If all entries need to be iterated better place them inside the Try-Catch
updateBatch(key,
xes -> {
for (int rowIndex : shouldBeReversed
) {
xes.remove((int) rowIndex); // will return an IndexOutOfBoundsException if not sorted in reverse
}
return xes;
}
);
} catch (IndexOutOfBoundsException e) {
throw new IndexOutOfBoundsException(e.getMessage() + "\n" +
"Reason: Batch indexes (Entry's value \"List<Integer>\") should be sorted in reverse order before submission");
}
如果需要条件(已排序或未排序),则
catch()
正文可用作“未排序”选项。
当然,这是非常非常具体的案例,但似乎为了获得布尔值而检查排序顺序似乎太多(?),特别是在迭代中。