Mit Python 3.x habe ich eine Liste von Zeichenfolgen, für die ich eine natürliche alphabetische Sortierung durchführen möchte.
Natürliche Sortierung: Die Reihenfolge, in der Dateien in Windows sortiert werden.
Zum Beispiel ist die folgende Liste natürlich sortiert (was ich will):
['elm0', 'elm1', 'Elm2', 'elm9', 'elm10', 'Elm11', 'Elm12', 'elm13']
Und hier ist die "sortierte" Version der obigen Liste (was ich habe):
['Elm11', 'Elm12', 'Elm2', 'elm0', 'elm1', 'elm10', 'elm13', 'elm9']
Ich suche eine Sortierfunktion, die sich wie die erste verhält.
python
sorting
python-3.x
snakile
quelle
quelle
!1, 1, !a, a
. Die einzige Möglichkeit, wie Windows zu sortieren, scheint darin zu bestehen, die Windows-StrCmpLogicalW
Funktion selbst zu verwenden, da diese Funktion anscheinend niemand korrekt implementiert hat (Quelle wäre willkommen). Lösung: stackoverflow.com/a/48030307/2441026Antworten:
Auf PyPI gibt es dafür eine Drittanbieter-Bibliothek namens natsort (vollständige Offenlegung, ich bin der Autor des Pakets). Für Ihren Fall können Sie eine der folgenden Aktionen ausführen:
Sie sollten beachten, dass
natsort
ein allgemeiner Algorithmus verwendet wird, damit er für nahezu jede Eingabe funktioniert, die Sie darauf werfen. Wenn Sie weitere Informationen darüber wünschen, warum Sie möglicherweise eine Bibliothek auswählen, um dies zu tun, anstatt Ihre eigene Funktion zu erweitern, lesen Sie die Seite Funktionsweise dernatsort
Dokumentation , insbesondere die Sonderfälle überall! Sektion.Wenn Sie anstelle einer Sortierfunktion einen Sortierschlüssel benötigen, verwenden Sie eine der folgenden Formeln.
quelle
natsort
behandelt 'natürlich' auch den Fall mehrerer separater Zahlen in den Zeichenfolgen. Tolles Zeug!Versuche dies:
Ausgabe:
Von hier angepasster Code: Sortieren für Menschen: Natürliche Sortierreihenfolge .
quelle
return sorted(l, key)
stattl.sort(key)
? Ist es für einen Leistungsgewinn oder nur um pythonischer zu sein?re.split('([0-9]+)', '0foo')
zurückkehrt['', '0', 'foo']
. Aus diesem Grund befinden sich Zeichenfolgen immer in geraden Indizes und Ganzzahlen in ungeraden Indizes im Array.Hier ist eine viel pythonischere Version von Mark Byers Antwort:
Nun kann diese Funktion als Schlüssel in einem beliebigen Funktion verwendet werden , die es verwendet, wie
list.sort
,sorted
,max
usw.Als Lambda:
quelle
Ich habe eine Funktion geschrieben, die auf http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html basiert und die Möglichkeit bietet, weiterhin Ihren eigenen 'Schlüssel'-Parameter zu übergeben. Ich brauche dies, um eine natürliche Art von Listen auszuführen, die komplexere Objekte enthalten (nicht nur Zeichenfolgen).
Beispielsweise:
quelle
natural_sort_key
, und dann, wenn Sie eine Liste sortieren, könnten Sie Ihre Schlüssel verketten, zB:list.sort(key=lambda el: natural_sort_key(el['name']))
Lassen Sie uns die Daten analysieren. Die Ziffernkapazität aller Elemente beträgt 2. Und es gibt 3 Buchstaben im gemeinsamen wörtlichen Teil
'elm'
.Die maximale Länge des Elements beträgt also 5. Wir können diesen Wert erhöhen, um sicherzugehen (z. B. auf 8).
Vor diesem Hintergrund haben wir eine einzeilige Lösung:
ohne reguläre Ausdrücke und externe Bibliotheken!
Erläuterung:
quelle
width = max(data, key=len)
berechnen, was für die8
oben genannten Daten'{0:0>{width}}'.format(x, width=width)
Gegeben:
Ähnlich wie bei SergOs Lösung wäre ein 1-Liner ohne externe Bibliotheken :
oder
Erläuterung:
Diese Lösung nutzt das Schlüsselmerkmal sort eine Funktion zu definieren , die für die Sortierung verwendet werden. Da wir wissen, dass vor jeder Dateneingabe 'elm' steht, konvertiert die Sortierfunktion den Teil der Zeichenfolge nach dem 3. Zeichen (dh int (x [3:])) in eine Ganzzahl. Wenn sich der numerische Teil der Daten an einer anderen Stelle befindet, müsste sich dieser Teil der Funktion ändern.
Prost
quelle
Es gibt viele Implementierungen, und während einige nahe gekommen sind, hat keine die Eleganz, die moderne Python bietet, ganz eingefangen.
Vorsicht bei der Verwendung
from os.path import split
Inspiration von
quelle
Wert dieses Beitrags
Mein Ziel ist es, eine Nicht-Regex-Lösung anzubieten, die allgemein angewendet werden kann.
Ich werde drei Funktionen erstellen:
find_first_digit
was ich von @AnuragUniyal ausgeliehen habe . Es wird die Position der ersten Ziffer oder Nicht-Ziffer in einer Zeichenfolge gefunden.split_digits
Dies ist ein Generator, der eine Zeichenfolge in Ziffern- und Nicht-Ziffernblöcke aufteilt. Es werden auchyield
ganze Zahlen angezeigt, wenn es sich um eine Ziffer handelt.natural_key
wickelt sich einfachsplit_digits
in eintuple
. Dies ist , was wir als Schlüssel verwenden fürsorted
,max
,min
.Funktionen
Wir können sehen, dass es allgemein ist, dass wir mehrstellige Chunks haben können:
Oder als Groß- und Kleinschreibung beachten:
Wir können sehen, dass die Liste des OP in der richtigen Reihenfolge sortiert wird
Es kann aber auch kompliziertere Listen verarbeiten:
Mein Regex-Äquivalent wäre
quelle
Eine Möglichkeit besteht darin, die Zeichenfolge in ein Tupel umzuwandeln und Ziffern mithilfe des erweiterten Formulars http://wiki.answers.com/Q/What_does_expanded_form_mean zu ersetzen
auf diese Weise würde a90 ("a", 90,0) und a1 ("a", 1) werden
Im Folgenden finden Sie einen Beispielcode (der aufgrund der Art und Weise, wie führende Nullen aus Zahlen entfernt werden, nicht sehr effizient ist.)
Ausgabe:
quelle
('b', 1) < ('b', 'e', 't', 'a', 1, '.', 1)
wird zurückkehrenTypeError: unorderable types: int() < str()
natsort
, pypi.org/project/natsortBasierend auf den Antworten hier habe ich eine
natural_sorted
Funktion geschrieben, die sich wie die eingebaute Funktion verhältsorted
:Der Quellcode ist auch in meinem GitHub-Snippets-Repository verfügbar: https://github.com/bdrung/snippets/blob/master/natural_sorted.py
quelle
Die obigen Antworten sind gut für das spezifische Beispiel , das gezeigt wurde, aber es fehlen einige nützliche Fälle für die allgemeinere Frage der natürlichen Art. Ich bin gerade von einem dieser Fälle gebissen worden und habe eine gründlichere Lösung gefunden:
Testcode und mehrere Links (ein- und ausschalten von StackOverflow) finden Sie hier: http://productarchitect.com/code/better-natural-sort.py
Feedback willkommen. Das soll keine endgültige Lösung sein. nur ein Schritt vorwärts.
quelle
natsorted
und dashumansorted
fehlschlägt, weil sie falsch verwendet wurden ... Sie haben versucht,natsorted
als Schlüssel zu übergeben, aber es ist eigentlich die Sortierfunktion selbst. Du hättest es versuchen sollennatsort_keygen()
.Höchstwahrscheinlich
functools.cmp_to_key()
hängt es eng mit der zugrunde liegenden Implementierung der Python-Sortierung zusammen. Außerdem ist der Parameter cmp ein Legacy. Die moderne Methode besteht darin, die Eingabeelemente in Objekte umzuwandeln, die die gewünschten umfangreichen Vergleichsoperationen unterstützen.Unter CPython 2.x können Objekte unterschiedlicher Typen bestellt werden, auch wenn die jeweiligen Rich-Vergleichsoperatoren nicht implementiert wurden. Unter CPython 3.x müssen Objekte unterschiedlichen Typs den Vergleich explizit unterstützen. Siehe Wie vergleicht Python String und Int? die Links zur offiziellen Dokumentation . Die meisten Antworten hängen von dieser impliziten Reihenfolge ab. Für den Wechsel zu Python 3.x ist ein neuer Typ erforderlich, um Vergleiche zwischen Zahlen und Zeichenfolgen zu implementieren und zu vereinheitlichen.
Es gibt drei verschiedene Ansätze. Die erste verwendet verschachtelte Klassen, um den
Iterable
Vergleichsalgorithmus von Python zu nutzen . Der zweite rollt diese Verschachtelung in eine einzelne Klasse ab. Die dritte verzichtet auf Unterklassen,str
um sich auf die Leistung zu konzentrieren. Alle sind zeitgesteuert; Der zweite ist doppelt so schnell, während der dritte fast sechsmal schneller ist. Unterklassenstr
sind nicht erforderlich und waren wahrscheinlich an erster Stelle eine schlechte Idee, bringen jedoch gewisse Annehmlichkeiten mit sich.Die Sortierzeichen werden dupliziert, um die Reihenfolge nach Groß- und Kleinschreibung zu erzwingen, und die Groß- und Kleinschreibung ausgetauscht, um zu erzwingen, dass Kleinbuchstaben zuerst sortiert werden. Dies ist die typische Definition von "natürlicher Sorte". Ich konnte mich nicht für die Art der Gruppierung entscheiden. Einige bevorzugen möglicherweise Folgendes, was ebenfalls erhebliche Leistungsvorteile mit sich bringt:
Wo verwendet, werden die Vergleichsoperatoren auf die von eingestellt,
object
damit sie von nicht ignoriert werdenfunctools.total_ordering
.Natürliche Sortierung ist sowohl ziemlich kompliziert als auch vage als Problem definiert. Vergessen Sie nicht , laufen
unicodedata.normalize(...)
vorher, und betrachten den Einsatzstr.casefold()
stattstr.lower()
. Es gibt wahrscheinlich subtile Codierungsprobleme, die ich nicht berücksichtigt habe. Daher empfehle ich vorläufig die Natsort- Bibliothek. Ich warf einen kurzen Blick auf das Github-Repository. Die Code-Wartung war hervorragend.Alle Algorithmen, die ich gesehen habe, hängen von Tricks ab, wie dem Duplizieren und Verringern von Zeichen und dem Vertauschen von Groß- und Kleinschreibung. Während dies die Laufzeit verdoppelt, würde eine Alternative eine vollständige natürliche Reihenfolge des Eingabezeichensatzes erfordern. Ich denke nicht, dass dies Teil der Unicode-Spezifikation ist, und da es viel mehr Unicode-Ziffern als gibt
[0-9]
, wäre das Erstellen einer solchen Sortierung ebenso entmutigend. Wenn Sie Vergleiche mit Gebietsschema wünschen, bereiten Sie Ihre Zeichenfolgenlocale.strxfrm
gemäß Pythons Sortieranleitung vor .quelle
Lassen Sie mich meine eigene Meinung zu diesem Bedürfnis einreichen:
Wenn wir nun eine solche Liste haben:
Wir können den
key=
Kwarg einfach verwenden , um eine natürliche Sortierung durchzuführen:Der Nachteil hierbei ist natürlich, dass die Funktion wie jetzt Großbuchstaben vor Kleinbuchstaben sortiert.
Ich überlasse die Implementierung eines case-insenstive Grouper dem Leser :-)
quelle
Ich schlage vor, Sie verwenden einfach das
key
Schlüsselwortargument vonsorted
, um Ihre gewünschte Liste zu erhalten.Zum Beispiel:
quelle
a_51
wäre danacha500
, obwohl 500> 51Nach der Antwort von @Mark Byers finden Sie hier eine Anpassung, die den
key
Parameter akzeptiert und PEP8-kompatibler ist.Ich habe auch einen Kern gemacht
quelle
key
Parameter? Dies zeigt sich aber auch in der Antwort von @ beauburrierEine Verbesserung gegenüber Claudius Verbesserung gegenüber Mark Byers Antwort ;-)
Übrigens erinnert sich vielleicht nicht jeder daran, dass die Standardeinstellungen für Funktionsargumente zur
def
Zeit ausgewertet werdenquelle
Danksagung :
Bubble Sort Hausaufgaben
Wie man eine Zeichenfolge in Python buchstabenweise liest
quelle
quelle