Ich möchte Gruppen fortlaufender Zahlen in einer Liste identifizieren, damit:
myfunc([2, 3, 4, 5, 12, 13, 14, 15, 16, 17, 20])
Kehrt zurück:
[(2,5), (12,17), 20]
Und ich habe mich gefragt, was der beste Weg ist, dies zu tun (insbesondere, wenn in Python etwas eingebaut ist).
Bearbeiten: Hinweis Ich habe ursprünglich vergessen zu erwähnen, dass einzelne Nummern als einzelne Nummern und nicht als Bereiche zurückgegeben werden sollten.
python
list
range
continuous
Mikemaccana
quelle
quelle
Antworten:
more_itertools.consecutive_groups
wurde in Version 4.0 hinzugefügt.Demo
Code
Mit diesem Tool erstellen wir eine Generatorfunktion, die Bereiche fortlaufender Zahlen findet.
Die Source - Implementierung emuliert eine klassische Rezeptur (wie durch @Nadia Alramli gezeigt).
Hinweis:
more_itertools
Ist ein Paket eines Drittanbieters, das über installiert werden kannpip install more_itertools
.quelle
EDIT 2: Um die neue OP-Anforderung zu beantworten
Ausgabe:
Sie können xrange durch range oder eine andere benutzerdefinierte Klasse ersetzen.
Python-Dokumente haben ein sehr ordentliches Rezept dafür:
Ausgabe:
Wenn Sie genau die gleiche Ausgabe erhalten möchten, können Sie dies tun:
Ausgabe:
EDIT: Das Beispiel ist bereits in der Dokumentation erklärt, aber vielleicht sollte ich es mehr erklären:
Wenn die Daten waren:
[2, 3, 4, 5, 12, 13, 14, 15, 16, 17]
Danngroupby(enumerate(data), lambda (i,x):i-x)
entspricht dies den folgenden:Die Lambda-Funktion subtrahiert den Elementindex vom Elementwert. Also, wenn Sie das Lambda auf jeden Artikel anwenden. Sie erhalten die folgenden Schlüssel für groupby:
groupby gruppiert Elemente nach gleichem Schlüsselwert, sodass die ersten 4 Elemente zusammen gruppiert werden und so weiter.
Ich hoffe das macht es lesbarer.
python 3
Version kann für Anfänger hilfreich seinImportieren Sie zuerst die erforderlichen Bibliotheken
quelle
lambda x:x[0]-x[1]
.[2,3,4,5] == xrange(2,6)
, nichtxrange(2,5)
. Es kann sinnvoll sein, einen neuen Datentyp für den inklusiven Bereich zu definieren.for key, group in groupby(enumerate(data), lambda i: i[0] - i[1]): group = list(map(itemgetter(1), group))
Die "naive" Lösung, die ich zumindest etwas lesbar finde.
quelle
print([i if i[0] != i[1] else i[0] for i in group(x)])
Angenommen, Ihre Liste ist sortiert:
quelle
[j - i for i, j in enumerate(lst)]
ist schlau :-)Hier sollte es funktionieren, ohne dass ein Import erforderlich ist:
quelle
Bitte beachten Sie, dass der verwendete Code
groupby
nicht wie in Python 3 angegeben funktioniert. Verwenden Sie diesen Code .quelle
Dies verwendet keine Standardfunktion - es iteriert nur über die Eingabe, aber es sollte funktionieren:
Beachten Sie, dass die Eingabe nur positive Zahlen in aufsteigender Reihenfolge enthalten muss. Sie sollten die Eingabe validieren, aber dieser Code wird aus Gründen der Übersichtlichkeit weggelassen.
quelle
Hier ist die Antwort, die ich mir ausgedacht habe. Ich schreibe den Code, damit andere ihn verstehen, also bin ich ziemlich ausführlich mit Variablennamen und Kommentaren.
Zuerst eine schnelle Hilfsfunktion:
Und dann der eigentliche Code:
Beispiellauf:
kehrt zurück:
quelle
>>> getranges([2, 12, 13])
Ausgänge :[[12, 13]]
. War das beabsichtigt?Ausgabe:
quelle
Die Verwendung von
groupby
undcount
vonitertools
gibt uns eine kurze Lösung. Die Idee ist, dass in zunehmender Reihenfolge die Differenz zwischen dem Index und dem Wert gleich bleibt.Um den Index zu verfolgen, können wir eine itertools.count verwenden , die den Code sauberer macht als
enumerate
:Einige Beispielausgaben:
quelle
Verwenden von numpy + -Verständnislisten:
Mit der numpy diff-Funktion können nachfolgende Eingabevektoreinträge identifiziert werden, deren Differenz nicht gleich eins ist. Der Anfang und das Ende des Eingabevektors müssen berücksichtigt werden.
Ausgabe:
Hinweis: Die Anforderung, dass einzelne Nummern unterschiedlich behandelt werden sollen (als einzelne zurückgegeben, nicht als Bereiche), wurde weggelassen. Dies kann durch weitere Nachbearbeitung der Ergebnisse erreicht werden. Normalerweise wird dies die Dinge komplexer machen, ohne einen Nutzen daraus zu ziehen.
quelle
Eine kurze Lösung, die ohne zusätzliche Importe funktioniert. Es akzeptiert alle iterierbaren Elemente, sortiert unsortierte Eingaben und entfernt doppelte Elemente:
Beispiel:
Dies ist das Gleiche wie die Lösung von @ dansalmo, die ich erstaunlich fand, wenn auch etwas schwer zu lesen und anzuwenden (da sie nicht als Funktion angegeben ist).
Beachten Sie, dass es leicht geändert werden kann, um "traditionelle" offene Bereiche auszuspucken
[start, end)
, indem z. B. die return-Anweisung geändert wird:Ich habe diese Antwort von einer anderen Frage kopiert , die als Duplikat dieser Frage markiert war, um sie leichter auffindbar zu machen (nachdem ich gerade wieder nach diesem Thema gesucht hatte, zuerst nur die Frage hier gefunden hatte und mit den Antworten nicht zufrieden war gegeben).
quelle
Die Versionen von Mark Byers , Andrea Ambu , SilentGhost , Nadia Alramli und Truppo sind einfach und schnell. Die 'Truppo'-Version ermutigte mich, eine Version zu schreiben, die das gleiche flinke Verhalten beibehält, während andere Schrittgrößen als 1 behandelt werden (und als Singletons-Elemente aufgeführt werden, die mit einer bestimmten Schrittgröße nicht mehr als 1 Schritt erweitern). Es ist hier gegeben .
quelle