Gibt es eine pythonische Möglichkeit zu überprüfen, ob eine Liste bereits in ASC
oder sortiert ist?DESC
listtimestamps = [1, 2, 3, 5, 6, 7]
so etwas isttimestamps.isSorted()
kehrt zurück True
oder False
.
Ich möchte eine Liste von Zeitstempeln für einige Nachrichten eingeben und prüfen, ob die Transaktionen in der richtigen Reihenfolge angezeigt wurden.
key
.key=lambda x, y: x < y
macht einen guten Standard.def isSorted(x, key = lambda x: x): return all([key(x[i]) <= key(x[i + 1]) for i in xrange(len(x) - 1)])
operator.le
sollte schneller sein als das Lambdal = [1, 2, 3, 4, 1, 6, 7, 8, 7] all(l[i] <= l[i+1] for i in xrange(len(l)-1))
True
xrange
mehr hat, nur verwendenrange
. Ich bekomme,NameError: name 'xrange' is not defined
wenn ich diesen Code ausführe. Ich habe es auf nurrange
statt umgestelltxrange
und das funktioniert gut. Siehe: stackoverflow.com/questions/15014310/…Ich würde nur verwenden
Es sei denn, es handelt sich um eine sehr große Liste. In diesem Fall möchten Sie möglicherweise eine benutzerdefinierte Funktion erstellen.
Wenn Sie es nur sortieren möchten, wenn es nicht sortiert ist, vergessen Sie die Prüfung und sortieren Sie es.
und denke nicht zu viel darüber nach.
Wenn Sie eine benutzerdefinierte Funktion wünschen, können Sie so etwas tun
Dies ist O (n), wenn die Liste bereits sortiert ist (und O (n) in einer
for
Schleife! ). Wenn Sie also nicht erwarten, dass sie die meiste Zeit nicht sortiert (und ziemlich zufällig) ist, würde ich Wieder sortieren Sie einfach die Liste.quelle
Diese Iteratorform ist 10-15% schneller als die Ganzzahlindizierung:
quelle
izip
undislice
von itertools verwenden, um es schneller zu machen.Eine schöne Möglichkeit, dies zu implementieren, ist die Verwendung der
imap
Funktion vonitertools
:Diese Implementierung ist schnell und funktioniert mit allen Iterables.
quelle
is_sorted(iter([1,2,3,2,5,8]))
oder einen gleichwertigen Generator. Sie müssen einen unabhängigen Iterator verwendentail
, um es zu versuchenitertools.tee
.iter(x) is x
für Iteratorenitertools.imap
umbenannt wurde[__builtins__.]map
.Ich habe einen Benchmark durchgeführt
und. Diese Benchmarks wurden auf einem MacBook Pro 2010 13 "(Core2 Duo 2,66 GHz, 4 GB 1067 MHz DDR3-RAM, Mac OS X 10.6.5) ausgeführt.sorted(lst, reverse=True) == lst
war der schnellste für lange Listen undall(l[i] >= l[i+1] for i in xrange(len(l)-1))
der schnellste für kurze ListenUPDATE: Ich habe das Skript überarbeitet, damit Sie es direkt auf Ihrem eigenen System ausführen können. Die vorherige Version hatte Fehler. Außerdem habe ich sowohl sortierte als auch unsortierte Eingaben hinzugefügt.all(l[i] >= l[i+1] for i in xrange(len(l)-1))
sorted(l, reverse=True) == l
all(l[i] >= l[i+1] for i in xrange(len(l)-1))
all(l[i] >= l[i+1] for i in xrange(len(l)-1))
In den meisten Fällen gibt es also einen klaren Gewinner.UPDATE: Die Antworten von aaronsterling (Nr. 6 und Nr. 7) sind in allen Fällen die schnellsten. # 7 ist am schnellsten, da es keine Indirektionsebene zum Nachschlagen des Schlüssels gibt.
quelle
enumerate
sind falsch.enumerate(l[1:])
sollte ersetzt werden durchenumerate(l[1:], 1)
enumerate(l[1:])
durchenumerate(l[1:], 1)
könnte ersetzen Siel[i-1]
durchl[i]
.L5=range(100); random.shuffle(L5)
ist # 5 vergleichsweise langsam. In diesem Fall ist die modifizierte # 7 insgesamt schneller codepad.org/xmWPxHQYIch würde dies tun (viele Antworten hier stehlen [Aaron Sterling, Wai Yip Tung, sorta von Paul McGuire] und hauptsächlich Armin Ronacher ):
Eine schöne Sache: Sie müssen die zweite Iteration für die Serie nicht realisieren (im Gegensatz zu einem Listen-Slice).
quelle
key
.key
sollte verwendet werden, um Elemente in vergleichbare Werte umzuwandeln.Ich benutze diesen Einzeiler basierend auf numpy.diff ():
Ich habe es nicht wirklich mit einer anderen Methode verglichen, aber ich gehe davon aus, dass es schneller ist als jede reine Python-Methode, insbesondere für große n, da die Schleife in numpy.diff (wahrscheinlich) direkt in C ausgeführt wird (n-1-Subtraktionen gefolgt von n) -1 Vergleiche).
Sie müssen jedoch vorsichtig sein, wenn x ein int ohne Vorzeichen ist, was zu einem stillen Ganzzahlunterlauf in numpy.diff () führen kann, was zu einem falsch positiven Ergebnis führt. Hier ist eine modifizierte Version:
quelle
Dies ähnelt der Top-Antwort, gefällt mir aber besser, da dadurch eine explizite Indizierung vermieden wird. Angenommen, Ihre Liste hat den Namen
lst
, können Sie(item, next_item)
Tupel aus Ihrer Liste generieren mitzip
:In Python 3 wird
zip
bereits ein Generator zurückgegeben, in Python 2 können Sieitertools.izip
für eine bessere Speichereffizienz verwenden.Kleine Demo:
Der letzte schlägt fehl, wenn das Tupel
(3, 2)
ausgewertet wird.Bonus: Überprüfung endlicher (!) Generatoren, die nicht indiziert werden können:
Stellen Sie sicher, dass Sie
itertools.izip
hier verwenden, wenn Sie Python 2 verwenden, da Sie sonst den Zweck umgehen würden, keine Listen von den Generatoren erstellen zu müssen.quelle
islice
Optimierung für das Schneiden verwenden. Auch im itertools-Modul.all(x <= y for x, y in izip(lst, islice(lst, 1)))
.SapphireSun ist ganz richtig. Sie können einfach verwenden
lst.sort()
. Die Sortierimplementierung (TimSort) von Python prüft, ob die Liste bereits sortiert ist. In diesem Fall wird sort () in linearer Zeit abgeschlossen. Klingt nach einer pythonischen Methode, um sicherzustellen, dass eine Liste sortiert ist;)quelle
Obwohl ich nicht glaube, dass es eine Garantie dafür gibt, dass das
sorted
integrierte System seine CMP-Funktion aufrufti+1, i
, scheint dies für CPython der Fall zu sein.Sie könnten also so etwas tun:
Oder so (ohne wenn Aussagen -> EAFP schief gelaufen sind? ;-)):
quelle
Überhaupt nicht sehr pythonisch, aber wir brauchen mindestens eine
reduce()
Antwort, oder?Die Akkumulatorvariable speichert einfach diesen zuletzt überprüften Wert. Wenn ein Wert kleiner als der vorherige Wert ist, wird der Akkumulator auf unendlich gesetzt (und ist daher am Ende immer noch unendlich, da der 'vorherige Wert' immer größer als ist der aktuelle).
quelle
Wie von @aaronsterling festgestellt, ist die folgende Lösung die kürzeste und scheint am schnellsten zu sein, wenn das Array sortiert und nicht zu klein ist: def is_sorted (lst): return (sortiert (lst) == lst)
Wenn das Array die meiste Zeit nicht sortiert ist, ist es wünschenswert, eine Lösung zu verwenden, die nicht das gesamte Array scannt und False zurückgibt, sobald ein unsortiertes Präfix entdeckt wird. Das Folgende ist die schnellste Lösung, die ich finden konnte, sie ist nicht besonders elegant:
Mit dem Benchmark von Nathan Farrington wird in allen Fällen eine bessere Laufzeit erzielt als mit sortiert (lst), außer wenn auf der großen sortierten Liste ausgeführt wird.
Hier sind die Benchmark-Ergebnisse auf meinem Computer.
sortiert (lst) == lst Lösung
Zweite Lösung:
quelle
Wenn Sie den schnellsten Weg für Numpy-Arrays suchen, verwenden Sie Numba . Wenn Sie Conda verwenden, sollte es bereits installiert sein
Der Code ist schnell, da er von numba kompiliert wird
und dann:
quelle
Nur um einen anderen Weg hinzuzufügen (auch wenn ein zusätzliches Modul erforderlich ist)
iteration_utilities.all_monotone
::So überprüfen Sie die DESC-Bestellung:
Es gibt auch einen
strict
Parameter, wenn Sie streng nach monotonen Sequenzen suchen müssen (wenn aufeinanderfolgende Elemente nicht gleich sein sollten).In Ihrem Fall ist dies kein Problem, aber wenn Ihre Sequenzen
nan
Werte enthalten, schlagen einige Methoden fehl, z. B. mit sortiert:Beachten Sie, dass
iteration_utilities.all_monotone
die Leistung im Vergleich zu den anderen hier genannten Lösungen insbesondere bei unsortierten Eingaben schneller ist (siehe Benchmark ).quelle
Faul
quelle
all(a <= b for a, b in zip(l, l[1:]))
l
es sich um einen Generator handelt und das Slicing nicht unterstützt.Python 3.6.8
quelle
Einfachster Weg:
quelle
Der abgeleitete Reduktionswert ist ein dreiteiliges Tupel von ( sortiertSoFarFlag , firstTimeFlag , lastElementValue ). Es beginnt zunächst mit (
True
,True
,None
), das auch als das Ergebnis für eine leere Liste verwendet wird (gilt als sortiert , weil es keine Out-of-Order - Elemente). Während es jedes Element verarbeitet, berechnet es neue Werte für das Tupel (unter Verwendung vorheriger Tupelwerte mit dem nächsten elementValue):Das Endergebnis der Reduzierung ist ein Tupel von:
Der erste Wert ist derjenige, an dem wir interessiert sind, also verwenden wir ihn
[0]
, um ihn aus dem Reduzierungsergebnis zu ziehen.quelle
Da ich diese Option oben nicht sehe, werde ich sie allen Antworten hinzufügen. Bezeichne die Liste mit
l
, dann:quelle
Eine Lösung mit Zuweisungsausdrücken (hinzugefügt in Python 3.8):
Gibt:
quelle
Dies ist in der Tat der kürzeste Weg, dies mithilfe der Rekursion zu tun:
Wenn es sortiert ist, wird True ausgegeben, andernfalls wird False gedruckt
quelle
RuntimeError: maximum recursion depth exceeded
für lange Listen ausgelöst wird. Versuchen Sie esany_list = range(1000)
.Wie wäre es mit diesem ? Einfach und unkompliziert.
quelle
Funktioniert definitiv in Python 3 und höher für Ganzzahlen oder Zeichenfolgen:
================================================== ===================
Eine andere Möglichkeit festzustellen, ob die angegebene Liste sortiert ist oder nicht
quelle