web-dev-qa-db-fra.com

Comment déterminer si une liste est triée en Java?

Je voudrais une méthode qui prend un List<T>T implémente Comparable et renvoie true ou false selon que la liste est triée ou non.

Quelle est la meilleure façon de l'implémenter en Java? Il est évident que les génériques et les caractères génériques sont censés être capables de gérer de telles choses facilement, mais je m'embrouille tous.

Il serait également agréable d'avoir une méthode analogue pour vérifier si la liste est dans l'ordre inverse.

55
Eric Wilson

Guava fournit cette fonctionnalité grâce à son impressionnante classe Ordering . Un Ordering est un Comparator ++. Dans ce cas, si vous avez une liste d'un type qui implémente Comparable, vous pouvez écrire:

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

Cela fonctionne pour tout Iterable, pas seulement List, et vous pouvez gérer nulls facilement en spécifiant s'ils doivent venir avant ou après tout autre nonnull éléments:

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

De plus, puisque vous avez mentionné que vous aimeriez pouvoir vérifier l'ordre inverse aussi bien que normal, cela se ferait comme:

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

Utilisateurs de Java 8 : Utilisez à la place l'équivalent Comparators#isInOrder(Iterable), car le reste de Ordering est principalement obsolète (comme expliqué dans la classe - documentation ).

103
ColinD

Voici une méthode générique qui fera l'affaire:

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
Sean

Facile:

List tmp = new ArrayList(myList);
Collections.sort(tmp);
boolean sorted = tmp.equals(myList);

Ou (si les éléments sont comparables):

Object prev;
for( Object elem : myList ) {
    if( prev != null && prev.compareTo(elem) > 0 ) {
        return false;
    }
    prev = elem;
}
return true;

Ou (si les éléments ne sont pas comparables):

Object prev;
for( Object elem : myList ) {
    if( prev != null && myComparator.compare(prev,elem) > 0 ) {
        return false;
    }
    prev = elem;
}
return true;

Les implémentations échouent pour les listes contenant des valeurs nulles. Vous devez ajouter des vérifications appropriées dans ce cas.

16
Daniel

Si vous utilisez Java 8, les flux peuvent être utiles.

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

Ce code triera la liste à sa place et collectera ses éléments dans une autre liste, qui sera ensuite comparée à la liste initiale. La comparaison réussira si les deux listes contiennent les mêmes éléments dans des positions égales.

Cette méthode n'est peut-être pas la solution la plus rapide mais elle est la plus simple à implémenter, qui n'implique pas de frameworks tiers.

13
Palle

Pour vérifier si une liste ou une structure de données est une tâche qui ne prend que O(n) temps. Parcourez simplement la liste à l'aide de l'interface Iterator et parcourez les données (dans votre cas, vous les avez déjà prêtes comme un type de comparable) du début à la fin et vous pouvez déterminer si elles sont triées ou pas facilement

5
bragboy
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 pas sûr les gars de ce que vous faites, mais cela peut être fait en boucle simple.

3
digitebs

Utilisez simplement l'itérateur pour parcourir le contenu du 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
jjnguy

Si vous en avez besoin pour les tests unitaires, vous pouvez utiliser AssertJ . Il contient une assertion pour vérifier si une liste est triée:

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

Il existe également une méthode alternative isSortedAccordingTo qui prend un comparateur au cas où vous voudriez utiliser un comparateur personnalisé pour le tri.

2
Wim Deblauwe

Il s'agit d'une opération qui prendra O(n) temps (pire des cas). Vous devrez gérer deux cas: où la liste est triée dans l'ordre décroissant et où la liste est triée dans ordre croissant.

Vous devrez comparer chaque élément avec l'élément suivant tout en vous assurant que l'ordre est préservé.

1
Vivin Paliath

Voici ce que je ferais:

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

Une implémentation simple sur les tableaux:

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

Conversion pour les listes:

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

Voici une méthode utilisant un Iterable et un 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;
}

Et une méthode pour un Iterable de Comparable et un indicateur pour la commande.

<T extends Comparable<? super T>> boolean isSorted(
        Iterable<? extends T> iterable, boolean natural) {
    return isSorted(iterable, natural ? naturalOrder() : reverseOrder());
}
0
Jin Kwon

Utilisation de Java 8 flux:

boolean isSorted = IntStream.range(1, list.size())
        .map(index -> list.get(index - 1).compareTo(list.get(index)))
        .allMatch(order -> order <= 0);

Cela fonctionne également pour les listes vides. Il n'est cependant efficace que pour les listes qui implémentent également l'interface de marqueur RandomAccess (par exemple, ArrayList).

0
sakra