Façon pythonique de vérifier si une liste est triée ou non

Existe-t-il un moyen pythonique de vérifier si une liste est déjà triée dans ASC ou DESC

listtimestamps = [1, 2, 3, 5, 6, 7]

Quelque Chose comme isttimestamps.isSorted() qui retourne True ou False.

Je veux entrer une liste d'horodatages pour certains messages et vérifier si les transactions sont apparues dans le bon ordre.

102
demandé sur nbro 2010-09-21 00:15:14

19 réponses

En fait, nous ne donnons pas la réponse qu'anijhaw cherche. Voici le One liner:

all(l[i] <= l[i+1] for i in xrange(len(l)-1))

Pour Python 3:

all(l[i] <= l[i+1] for i in range(len(l)-1))
156
répondu Wai Yip Tung 2018-01-29 14:08:41

, je voudrais juste utiliser

if sorted(lst) == lst:
    # code here

Sauf si c'est une très grande liste, auquel cas vous voudrez peut-être créer une fonction personnalisée.

Si vous allez simplement le trier s'il n'est pas trié, oubliez la vérification et triez-la.

lst.sort()

Et n'y pense pas trop.

Si vous voulez une fonction personnalisée, vous pouvez faire quelque chose comme

def is_sorted(lst, key=lambda x: x):
    for i, el in enumerate(lst[1:]):
        if key(el) < key(lst[i]): # i is the index of the previous element
            return False
    return True

Ce sera O (n) si la liste est déjà triée (et O(N) dans une boucle for à cela! donc, à moins que vous l'attendez pas triés (et assez aléatoire) la plupart du temps, je voudrais, encore une fois, juste trier la liste.

60
répondu aaronasterling 2016-12-30 21:05:41

Cette forme d'itérateur est 10-15% plus rapide que l'utilisation de l'indexation entière:

# from itertools import izip as zip # python 2 only!

def is_sorted(l):
    return all(a <= b for a, b in zip(l, l[1:]))
31
répondu PaulMcG 2018-05-09 14:32:32

Une belle façon de l'implémenter est d'utiliser la fonction imap de itertools:

from itertools import imap, tee
import operator

def is_sorted(iterable, compare=operator.le):
  a, b = tee(iterable)
  next(b, None)
  return all(imap(compare, a, b))

Cette implémentation est rapide et fonctionne sur tous les itérables.

16
répondu Alexandre Vassalotti 2013-08-06 00:41:51

Je le ferais (voler de nombreuses réponses ici [Aaron Sterling, Wai Yip Tung, sorta de Paul McGuire] et surtout Armin Ronacher):

from itertools import tee, izip

def pairwise(iterable):
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

def is_sorted(iterable, key=lambda a, b: a <= b):
    return all(key(a, b) for a, b in pairwise(iterable))

Une bonne chose: vous n'avez pas besoin de réaliser la deuxième itérable pour la série (contrairement à une tranche de liste).

9
répondu hughdbrown 2015-03-22 19:19:38

J'ai couru un benchmark et sorted(lst, reverse=True) == lst était le plus rapide pour les listes longues, et all(l[i] >= l[i+1] for i in xrange(len(l)-1)) était le plus rapide pour les listes courtes. Ces benchmarks ont été exécutés sur un MacBook Pro 2010 13" (Core2 Duo 2.66 GHz, 4GB 1067MHz DDR3 RAM, Mac OS X 10.6.5).

UPDATE: j'ai révisé le script afin que vous puissiez l'exécuter directement sur votre propre système. La version précédente avait des insectes. En outre, j'ai ajouté des entrées triées et non triées.

  • meilleur pour les listes triées courtes: all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • meilleur pour les longues listes triées: sorted(l, reverse=True) == l
  • idéal pour les listes courtes non triées: all(l[i] >= l[i+1] for i in xrange(len(l)-1))
  • idéal pour les listes longues non triées: all(l[i] >= l[i+1] for i in xrange(len(l)-1))

Donc, dans la plupart des cas, il y a un gagnant clair.

Mise à jour: les réponses d'aaronsterling (#6 et #7) sont en fait les plus rapides dans tous les cas. #7 est le plus rapide car il n'a pas de couche d'indirection pour rechercher la clé.

#!/usr/bin/env python

import itertools
import time

def benchmark(f, *args):
    t1 = time.time()
    for i in xrange(1000000):
        f(*args)
    t2 = time.time()
    return t2-t1

L1 = range(4, 0, -1)
L2 = range(100, 0, -1)
L3 = range(0, 4)
L4 = range(0, 100)

# 1.
def isNonIncreasing(l, key=lambda x,y: x >= y): 
    return all(key(l[i],l[i+1]) for i in xrange(len(l)-1))
print benchmark(isNonIncreasing, L1) # 2.47253704071
print benchmark(isNonIncreasing, L2) # 34.5398209095
print benchmark(isNonIncreasing, L3) # 2.1916718483
print benchmark(isNonIncreasing, L4) # 2.19576501846

# 2.
def isNonIncreasing(l):
    return all(l[i] >= l[i+1] for i in xrange(len(l)-1))
print benchmark(isNonIncreasing, L1) # 1.86919999123
print benchmark(isNonIncreasing, L2) # 21.8603689671
print benchmark(isNonIncreasing, L3) # 1.95684289932
print benchmark(isNonIncreasing, L4) # 1.95272517204

# 3.
def isNonIncreasing(l, key=lambda x,y: x >= y): 
    return all(key(a,b) for (a,b) in itertools.izip(l[:-1],l[1:]))
print benchmark(isNonIncreasing, L1) # 2.65468883514
print benchmark(isNonIncreasing, L2) # 29.7504849434
print benchmark(isNonIncreasing, L3) # 2.78062295914
print benchmark(isNonIncreasing, L4) # 3.73436689377

# 4.
def isNonIncreasing(l):
    return all(a >= b for (a,b) in itertools.izip(l[:-1],l[1:]))
print benchmark(isNonIncreasing, L1) # 2.06947803497
print benchmark(isNonIncreasing, L2) # 15.6351969242
print benchmark(isNonIncreasing, L3) # 2.45671010017
print benchmark(isNonIncreasing, L4) # 3.48461818695

# 5.
def isNonIncreasing(l):
    return sorted(l, reverse=True) == l
print benchmark(isNonIncreasing, L1) # 2.01579380035
print benchmark(isNonIncreasing, L2) # 5.44593787193
print benchmark(isNonIncreasing, L3) # 2.01813793182
print benchmark(isNonIncreasing, L4) # 4.97615599632

# 6.
def isNonIncreasing(l, key=lambda x, y: x >= y): 
    for i, el in enumerate(l[1:]):
        if key(el, l[i-1]):
            return False
    return True
print benchmark(isNonIncreasing, L1) # 1.06842684746
print benchmark(isNonIncreasing, L2) # 1.67291283607
print benchmark(isNonIncreasing, L3) # 1.39491200447
print benchmark(isNonIncreasing, L4) # 1.80557894707

# 7.
def isNonIncreasing(l):
    for i, el in enumerate(l[1:]):
        if el >= l[i-1]:
            return False
    return True
print benchmark(isNonIncreasing, L1) # 0.883186101913
print benchmark(isNonIncreasing, L2) # 1.42852401733
print benchmark(isNonIncreasing, L3) # 1.09229516983
print benchmark(isNonIncreasing, L4) # 1.59502696991
7
répondu Nathan Farrington 2010-12-09 23:54:33

Bien que je ne pense pas qu'il y ait une garantie pour que le sorted intégré appelle sa fonction cmp avec i+1, i, il semble le faire pour CPython.

Donc vous pouvez faire quelque chose comme:

def my_cmp(x, y):
   cmpval = cmp(x, y)
   if cmpval < 0:
      raise ValueError
   return cmpval

def is_sorted(lst):
   try:
      sorted(lst, cmp=my_cmp)
      return True
   except ValueError:
      return False

print is_sorted([1,2,3,5,6,7])
print is_sorted([1,2,5,3,6,7])

Ou de cette façon (sans instructions if - > EAFP qui a mal tourné? ;-) ):

def my_cmp(x, y):
   assert(x >= y)
   return -1

def is_sorted(lst):
   try:
      sorted(lst, cmp=my_cmp)
      return True
   except AssertionError:
      return False
3
répondu Anthon 2012-05-28 20:21:24

Pas très pythonique du tout, mais nous avons besoin d'au moins une réponse reduce(), non?

def is_sorted(iterable):
    prev_or_inf = lambda prev, i: i if prev <= i else float('inf')
    return reduce(prev_or_inf, iterable, float('-inf')) < float('inf')

La variable accumulator stocke simplement cette dernière valeur vérifiée, et si une valeur est plus petite que la valeur précédente, l'accumulateur est défini sur infinity (et sera donc toujours infini à la fin, puisque la 'valeur précédente' sera toujours plus grande que la valeur actuelle).

3
répondu orlade 2012-08-08 05:13:44

J'utilise ce one-liner basé sur numpy.diff ():

def issorted(x):
    """Check if x is sorted"""
    return (numpy.diff(x) >= 0).all() # is diff between all consecutive entries >= 0?

Je ne l'ai pas vraiment chronométré contre une autre méthode, mais je suppose que c'est plus rapide que toute méthode Python pure, en particulier pour les gros n, Depuis la boucle dans numpy.diff (probablement) s'exécute directement en C (soustractions n-1 suivies de comparaisons n-1).

Cependant, vous devez faire attention si x est un int non signé, ce qui peut provoquer un sous-flux entier silencieux dans numpy.diff (), résultant en un faux positif. Voici une modification version:

def issorted(x):
    """Check if x is sorted"""
    try:
        if x.dtype.kind == 'u':
            # x is unsigned int array, risk of int underflow in np.diff
            x = numpy.int64(x)
    except AttributeError:
        pass # no dtype, not an array
    return (numpy.diff(x) >= 0).all()
3
répondu Martin Spacek 2013-02-08 23:24:46

Ceci est similaire à la réponse supérieure, mais je l'aime mieux car cela évite l'indexation explicite. En supposant que votre liste a le nom lst, vous pouvez générer
(item, next_item) tuples de votre liste avec zip:

all(x <= y for x,y in zip(lst, lst[1:]))

En Python 3, zip renvoie déjà un générateur, en Python 2 Vous pouvez utiliser itertools.izip pour une meilleure efficacité de la mémoire.

Petite démo:

>>> lst = [1, 2, 3, 4]
>>> zip(lst, lst[1:])
[(1, 2), (2, 3), (3, 4)]
>>> all(x <= y for x,y in zip(lst, lst[1:]))
True
>>> 
>>> lst = [1, 2, 3, 2]
>>> zip(lst, lst[1:])
[(1, 2), (2, 3), (3, 2)]
>>> all(x <= y for x,y in zip(lst, lst[1:]))
False

Le dernier échoue lorsque le tuple (3, 2) est évaluée.

Bonus: vérification finie (!) générateurs qui ne peut pas être indexé:

>>> def gen1():
...     yield 1
...     yield 2
...     yield 3
...     yield 4
...     
>>> def gen2():
...     yield 1
...     yield 2
...     yield 4
...     yield 3
... 
>>> g1_1 = gen1()
>>> g1_2 = gen1()
>>> next(g1_2)
1
>>> all(x <= y for x,y in zip(g1_1, g1_2))
True
>>>
>>> g2_1 = gen2()
>>> g2_2 = gen2()
>>> next(g2_2)
1
>>> all(x <= y for x,y in zip(g2_1, g2_2))
False

Assurez-vous d'utiliser itertools.izip ici si vous utilisez Python 2, sinon vous vaincriez le but de ne pas avoir à créer des listes à partir des générateurs.

3
répondu timgeb 2016-02-19 00:15:29

Saphiresun a tout à fait raison. Vous pouvez simplement utiliser lst.sort(). L'implémentation de tri de Python (TimSort) vérifie si la liste est déjà triée. Si c'est le cas, sort () sera terminé en temps linéaire. Cela ressemble à un moyen pythonique de s'assurer qu'une liste est triée ;)

2
répondu Wai Yip Tung 2010-09-20 20:24:12

Comme noté par @ aaronsterling, la solution suivante est la plus courte et semble la plus rapide lorsque le tableau est trié et pas trop petit: def is_sorted(lst): retour (trié (lst) = = lst)

Si la plupart du temps le tableau n'est pas trié, il serait souhaitable d'utiliser une solution qui n'analyse pas tout le tableau et renvoie False dès qu'un préfixe non trié est découvert. Voici la solution la plus rapide que j'ai pu trouver, ce n'est pas particulièrement élégant:

def is_sorted(lst):
    it = iter(lst)
    try:
        prev = it.next()
    except StopIteration:
        return True
    for x in it:
        if prev > x:
            return False
        prev = x
    return True

Utilisation Le benchmark de Nathan Farrington, cela permet d'obtenir un meilleur temps d'exécution que d'utiliser tried(LST) dans tous les cas, sauf lors de l'exécution sur la grande liste triée.

Voici les résultats de référence sur mon ordinateur.

Trié (lst)==LST solution

  • L1: 1.23838591576
  • L2: 4.19063091278
  • L3: 1.17996287346
  • L4: 4.68399500847

Deuxième solution:

  • L1: 0.81095790863
  • L2: 0.802397012711
  • L3: 1.06135106087
  • L4: 8.82761001587
2
répondu Amit Moscovich 2012-05-28 13:02:00

Si vous voulez le moyen le plus rapide pour les tableaux numpy, utiliser numba, qui, si vous utilisez conda doit être déjà installé

Le code sera rapide, car il sera compilé par numba

import numba
@numba.jit
def issorted(vec, ascending=True):
    if len(vec) < 2:
        return True
    if ascending:
        for i in range(1, len(vec)):
            if vec[i-1] > vec[i]:
                return False
        return True
    else:
        for i in range(1, len(vec)):
            if vec[i-1] < vec[i]:
                return False
        return True

Puis:

>>> issorted(array([4,9,100]))
>>> True
2
répondu tal 2016-12-22 08:43:32

Juste pour ajouter une autre façon (même si elle nécessite un module supplémentaire): iteration_utilities.all_monotone:

>>> from iteration_utilities import all_monotone
>>> listtimestamps = [1, 2, 3, 5, 6, 7]
>>> all_monotone(listtimestamps)
True

>>> all_monotone([1,2,1])
False

Pour vérifier l'ordre DESC:

>>> all_monotone(listtimestamps, decreasing=True)
False

>>> all_monotone([3,2,1], decreasing=True)
True

Il y a aussi un paramètre strict Si vous devez vérifier les séquences strictement monotones (si les éléments successifs ne doivent pas être égaux).

Ce n'est pas un problème dans votre cas mais si vos séquences contiennent des valeurs nan alors certaines méthodes échoueront, par exemple avec tried:

def is_sorted_using_sorted(iterable):
    return sorted(iterable) == iterable

>>> is_sorted_using_sorted([3, float('nan'), 1])  # definetly False, right?
True

>>> all_monotone([3, float('nan'), 1])
False

Notez que iteration_utilities.all_monotone effectue plus rapide par rapport aux autres solutions mentionnées ici en particulier pour les entrées non triées (voir benchmark).

2
répondu MSeifert 2017-04-04 19:55:01

Paresseux

from itertools import tee

def is_sorted(l):
    l1, l2 = tee(l)
    next(l2, None)
    return all(a <= b for a, b in zip(l1, l2))
1
répondu Sergey11g 2018-09-07 14:11:38

C'est en fait le moyen le plus rapide de le faire en utilisant la récursivité:

S'il est trié imprimera True sinon imprimera False

 def is_Sorted(lst):
    if len(lst) == 1:
       return True
    return lst[0] <= lst[1] and is_Sorted(lst[1:])

 any_list = [1,2,3,4]
 print is_Sorted(any_list)
0
répondu Baraa 2016-02-19 00:28:03

Moyen le plus simple:

def isSorted(arr):
  i = 1
  while i < len(arr):
    if(result[i] < result[i - 1]):
      return False
    i += 1
  return True
0
répondu Aluis92 2018-07-23 17:38:27

Fonctionne définitivement en Python 3 et au-dessus pour les entiers ou les chaînes:

def tail(t):
    return t[:]

letters = ['a', 'b', 'c', 'd', 'e']
rest = tail(letters)
rest.sort()
if letters == rest:
    print ('Given list is SORTED.')
else:
    print ('List NOT Sorted.')

=====================================================================

Une autre façon de trouver si la liste donnée est triée ou non

trees1 = list ([1, 4, 5, 3, 2])
trees2 = list (trees1)
trees2.sort()
if trees1 == trees2:
    print ('trees1 is SORTED')
else:
    print ('Not sorted')
-1
répondu cooldeal 2015-05-19 10:38:48

Et celui-ci ? Simple et directe.

def is_list_sorted(al):

    llength =len(al)


    for i in range (llength):
        if (al[i-1] > al[i]):
            print(al[i])
            print(al[i+1])
            print('Not sorted')
            return -1

    else :
        print('sorted')
        return  true
-1
répondu Zuckerberg 2018-04-28 21:09:57