如何确定列表是否用Java排序?


73

我想要一种方法,该方法采用List<T>whereT实现Comparable并返回,true或者false取决于列表是否已排序。

用Java实现此的最佳方法是什么?显然,泛型和通配符是为了能够轻松处理此类事情,但我正陷入困境。

如果有一个类似的方法来检查列表是否是相反的顺序,那也很好。


您有机会改用排序的集合吗?或者只是根据需要调用.Sort()?
朱丽叶

1
这样做的目的是为了测试,所以没有。
埃里克·威尔逊

列表应该是升序还是降序?
若昂里斯本

我希望能够同时检查这两种类型,因为两种类型都会出现。
埃里克·威尔逊

1
@fuzzy棒棒糖-我希望以类型安全的方式实现此方法。
埃里克·威尔逊

Answers:


124

番石榴通过其出色的Ordering类提供了此功能。AnOrderingComparator++。在这种情况下,如果您具有实现的某种类型的列表Comparable,则可以编写:

boolean sorted = Ordering.natural().isOrdered(list);

这适用于任何Iterable,而不仅仅是List,并且您可以null通过指定s应该在其他任何非null元素之前还是之后轻松地处理s :

Ordering.natural().nullsLast().isOrdered(list);

另外,由于您提到您希望能够检查颠倒顺序和正常顺序,因此可以执行以下操作:

Ordering.natural().reverse().isOrdered(list);

Java 8用户:请改用等效的Java语言Comparators#isInOrder(Iterable),因为其余的Ordering大多已过时(如类文档中所述)。


8
还有,isStrictlyOrdered()如果您想确保没有重复项。
凯文·布瑞里恩

10
+1用于指向现有代码,以便人们停止重新发明事物并开始制作新事物。
只是我的正确观点2010年

如果没有自然顺序,并且您想传递一个,可以显示一个示例Comparator吗?我认为这Ordering.from是出于以下目的:“基于现有的比较器实例返回一个排序。请注意,不必创建一个新的匿名内部类来实现Comparator,只需将其传递到此处即可。相反,只需对Ordering子类化并直接实现其compare方法。”
丹尼尔·卡普兰

3
@tieTYT:您可以使用Ordering.from(comparator).isOrdered(list); 但是,如果您要自己实现比较器,则最好只是扩展Ordering而不是先实现Comparator,在这种情况下,它就是myOrdering.isOrdered(list)
ColinD 2014年

1
只是在这里留言。大多数命令已过时,但他们在此处删除了计划删除的注释。github.com/google/guava/commit/...
安德烈Bergonzo

27

这是可以解决问题的通用方法:

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

25

如果您使用的是Java 8或更高版本,流可能会有所帮助。

list.stream().sorted().collect(Collectors.toList()).equals(list);

此代码将对列表进行排序,并将其元素收集到另一个列表中,然后将其与初始列表进行比较。如果两个列表在相同位置包含相同元素,则比较将成功。

请注意,此方法将比其他方法具有更差的空间和时间复杂度,因为它将不得不对列表进行排序,因此,不应将其用于非常大的列表。但这是最容易使用的,因为它是单个表达式,并且不涉及第三方库。


1
很好...显然没有帮助2010年我使用Java 6,但这是一个很好的补充。
埃里克·威尔逊

3
比理想的少分配和少排序解决方案效率低得多。
Vadzim

根据Java 8文档,Collectors.toList(); 无法保证返回的{@code List}的类型,可变性,可序列化性或线程安全性;您应该使用ArrayList的供应商
johnlemon '17

3
看起来这与这种情况无关,因为生成的列表永远不会超过语句,因此它永远不会被序列化,变异或从多个线程访问。
Palle

21

简单:

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;

对于包含空值的列表,实现失败。在这种情况下,您必须添加适当的检查。


Collections.sort将要求列表元素已经具有可比性,无论如何这是问题中的规定。
Yishai 2010年

3
我认为您的第一个示例缺少一行,因为tmp没有填充。
埃里克·威尔逊

1
第一个示例所做的工作也很浪费,第二个示例中的对象必须是可比较的。
ColinD 2010年

@Daniel是否需要初始化prev?
摩西·基拉特

5

要检查列表或任何数据结构是否只需要O(n)时间的任务。只需使用IteratorInterface遍历列表,然后从头到尾遍历数据(在您的情况下,您已经准备好将其作为Comparable类型),就可以发现是否对其进行了排序


1
有趣的是,您的算法实际上是合理随机列表的O(1)期望时间。
mikera 2010年

1
在最坏的情况下(当列表确实排序时)为O(n)。
Jesper 2010年

5
-1,因为询问者已表明他在泛型和通配符之类的实现问题中变得“纠结”,我认为此答案只是告诉他他已经知道的事情。
凯文·布瑞里恩

5

如果需要进行单元测试,则可以使用AssertJ。它包含一个断言,以检查List是否已排序:

List<String> someStrings = ...
assertThat(someStrings).isSorted();

isSortedAccordingTo如果您想使用自定义比较器进行排序,还有一种替代方法可以使用比较器。


4
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不确定大家在做什么,但这可以通过简单的for循环来完成。


1
首先,公认的答案(Guava)中库的实现本质上是这样的:github.com/google/guava/blob / ... 但是IMO始终保持代码库小而不是重新实现库可以给您的东西总是更好的选择。
Ben Page

这比对数组排序并检查它们是否相等要好得多。
ShellFish

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

3
这将继续进行,因为previous将永远不会进行设置。请参阅丹尼尔的答案以确保正确流动。
BalusC 2010年

当然也将需要限制<T extends Comparable>
ColinD 2010年

@Colin(以及其他所有人)很抱歉,此编译不正确。我写得很快。科林,您具有编辑能力,可以随时修复我犯的这个错误。
jjnguy 2010年

我接受了避免使用原始类型的解决方案。不过,这是我的第二选择,所以我投票了。
埃里克·威尔逊

@FarmBoy,感谢您的反馈!很高兴我们可以提供帮助。
jjnguy 2010年

2

使用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)。

如果您无权访问流的基础集合,则可以使用以下丑陋的方法:

Stream<T> stream = ...
Comparator<? super T> comparator = ...
boolean isSorted = new AtomicInteger(0) {{
    stream.sequential()
          .reduce((left, right) -> {
               getAndUpdate(order -> (order <= 0) ? comparator.compare(left, right) : order);
               return right;
          });
}}.get() <= 0;

1

此操作将花费O(n)时间(最坏的情况)。您将需要处理两种情况:列表以降序排列,列表以升序排列。

您需要将每个元素与下一个元素进行比较,同时确保保留顺序。


1

这就是我要做的:

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

没用 public static void main(String [] args){List <Integer> list = Arrays.asList(1,2,9,7,4); System.out.println(isSorted(list)); }```期望输出false,但是输出true。
Mingjiang Shi

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

1
ps请注意,该实现是有意设计的,以避免分配迭代器或进行多次调用来获取。这是为使用ArrayList的常见情况而设计的,对于其他列表实现,可能最好使用迭代器。
mikera 2010年

可能在这种情况下做的一件事是检查是否List器具RandomAccess和使用,如果这样这个实现,一个Iterator如果没有实现。您实际上并不想按LinkedList原样使用它。
ColinD 2010年

@ColinD好主意!我猜您可以这样做,以便它也可以在编译时检测到该问题
mikera 2010年

0

这是使用anIterable和a的方法Comparator

<T> boolean isSorted(Iterable<? extends T> iterable,
                     Comparator<? super T> comparator) {
    boolean beforeFirst = true;
    T previous = null;
    for (final T current : iterable) {
        if (beforeFirst) {
            beforeFirst = false;
            previous = current;
            continue;
        }
        if (comparator.compare(previous, current) > 0) {
            return false;
        }
        previous = current;
    }
    return true;
}

以及一种用于IterableofComparable和标志的方法。

<T extends Comparable<? super T>> boolean isSorted(
        Iterable<? extends T> iterable, boolean natural) {
    return isSorted(iterable, natural ? naturalOrder() : reverseOrder());
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.