Wie verwende ich Pythons itertools.groupby()?
Frage
Ich konnte keine verständliche Erklärung dafür finden, wie man Pythons tatsächlich verwendet itertools.groupby()
Funktion.Was ich versuche, ist Folgendes:
- Erstellen Sie eine Liste – in diesem Fall die Kinder eines Objekts
lxml
Element - Teilen Sie es anhand einiger Kriterien in Gruppen ein
- Anschließend wird jede dieser Gruppen einzeln durchlaufen.
Ich habe es überprüft die Dokumentation, Und die Beispiele, aber es fiel mir schwer, sie über eine einfache Zahlenliste hinaus anzuwenden.
Also, wie verwende ich of itertools.groupby()
?Gibt es eine andere Technik, die ich verwenden sollte?Hinweise auf gute „Voraussetzungslektüre“ wären ebenfalls willkommen.
Lösung
WICHTIGER HINWEIS: Du musst Sortieren Sie Ihre Daten Erste.
Der Teil, den ich nicht verstanden habe, ist der in der Beispielkonstruktion
groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
k
ist der aktuelle Gruppierungsschlüssel und g
ist ein Iterator, den Sie zum Durchlaufen der durch diesen Gruppierungsschlüssel definierten Gruppe verwenden können.Mit anderen Worten, die groupby
Der Iterator selbst gibt Iteratoren zurück.
Hier ist ein Beispiel dafür mit klareren Variablennamen:
from itertools import groupby
things = [("animal", "bear"), ("animal", "duck"), ("plant", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]
for key, group in groupby(things, lambda x: x[0]):
for thing in group:
print "A %s is a %s." % (thing[1], key)
print " "
Dadurch erhalten Sie die Ausgabe:
Ein Bär ist ein Tier.
Eine Ente ist ein Tier.Ein Kaktus ist eine Pflanze.
Ein Schnellboot ist ein Fahrzeug.
Ein Schulbus ist ein Fahrzeug.
In diesem Beispiel, things
ist eine Liste von Tupeln, wobei das erste Element in jedem Tupel die Gruppe ist, zu der das zweite Element gehört.
Der groupby()
Die Funktion benötigt zwei Argumente:(1) die zu gruppierenden Daten und (2) die Funktion, mit der sie gruppiert werden sollen.
Hier, lambda x: x[0]
erzählt groupby()
um das erste Element in jedem Tupel als Gruppierungsschlüssel zu verwenden.
In obigem for
Stellungnahme, groupby
gibt drei Paare (Schlüssel, Gruppeniterator) zurück – einmal für jeden eindeutigen Schlüssel.Mit dem zurückgegebenen Iterator können Sie jedes einzelne Element in dieser Gruppe durchlaufen.
Hier ist ein etwas anderes Beispiel mit denselben Daten unter Verwendung eines Listenverständnisses:
for key, group in groupby(things, lambda x: x[0]):
listOfThings = " and ".join([thing[1] for thing in group])
print key + "s: " + listOfThings + "."
Dadurch erhalten Sie die Ausgabe:
Tiere:Bär und Ente.
Pflanzen:Kaktus.
Fahrzeuge:Schnellboot und Schulbus.
Andere Tipps
Können Sie uns Ihren Code zeigen?
Das Beispiel in den Python-Dokumenten ist recht einfach:
groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
In Ihrem Fall handelt es sich bei Daten also um eine Liste von Knoten, bei keyfunc handelt es sich um die Logik Ihrer Kriterienfunktion und dann groupby()
gruppiert die Daten.
Da muss man vorsichtig sein Sortieren Sie die Daten anhand der Kriterien, bevor Sie anrufen groupby
oder es wird nicht funktionieren. groupby
Die Methode durchläuft eigentlich nur eine Liste und erstellt bei jeder Schlüsseländerung eine neue Gruppe.
Ein netter Trick mit Groupby besteht darin, die Längenkodierung in einer Zeile auszuführen:
[(c,len(list(cgen))) for c,cgen in groupby(some_string)]
erhalten Sie eine Liste von 2-Tupeln, wobei das erste Element das Zeichen und das zweite die Anzahl der Wiederholungen ist.
Bearbeiten:Beachten Sie, dass dies das ist, was trennt itertools.groupby
aus dem SQL GROUP BY
Semantik:itertools sortiert den Iterator nicht im Voraus (und kann dies im Allgemeinen auch nicht), sodass Gruppen mit demselben „Schlüssel“ nicht zusammengeführt werden.
itertools.groupby
ist ein Werkzeug zum Gruppieren von Elementen.
Aus die Dokumente, erfahren wir weiter, was es bewirken könnte:
# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
groupby
Objekte ergeben Schlüssel-Gruppen-Paare, wobei die Gruppe ein Generator ist.
Merkmale
- A.Gruppieren Sie aufeinanderfolgende Elemente
- B.Gruppieren Sie alle Vorkommen eines Elements anhand einer sortierten Iterable
- C.Geben Sie an, wie Elemente mit einer Schlüsselfunktion gruppiert werden
Vergleiche
# Define a printer for comparing outputs
>>> def print_groupby(iterable, key=None):
... for k, g in it.groupby(iterable, key):
... print("key: '{}'--> group: {}".format(k, list(g)))
# Feature A: group consecutive occurrences
>>> print_groupby("BCAACACAADBBB")
key: 'B'--> group: ['B']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A', 'A']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A', 'A']
key: 'D'--> group: ['D']
key: 'B'--> group: ['B', 'B', 'B']
# Feature B: group all occurrences
>>> print_groupby(sorted("BCAACACAADBBB"))
key: 'A'--> group: ['A', 'A', 'A', 'A', 'A']
key: 'B'--> group: ['B', 'B', 'B', 'B']
key: 'C'--> group: ['C', 'C', 'C']
key: 'D'--> group: ['D']
# Feature C: group by a key function
>>> key = lambda x: x.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), key)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']
Verwendet
- Anagramme (siehe Notizbuch)
- Klasseneinteilung
- Gruppieren Sie ungerade und gerade Zahlen
- Gruppieren Sie eine Liste nach Werten
- Entfernen Sie doppelte Elemente
- Suchen Sie nach Indizes wiederholter Elemente in einem Array
- Teilen Sie ein Array in n-große Blöcke auf
- Finden Sie entsprechende Elemente zwischen zwei Listen
- Komprimierungsalgorithmus (siehe Notizbuch)/Lauflängenkodierung
- Buchstaben nach Länge gruppieren, Tastenfunktion (siehe Notizbuch)
- Aufeinanderfolgende Werte über einem Schwellenwert (siehe Notizbuch)
- Finden Sie Zahlenbereiche in einer Liste oder fortlaufende Artikel (sehen Dokumente)
- Finden Sie alle zugehörigen längsten Sequenzen
- Nehmen Sie aufeinanderfolgende Sequenzen, die eine Bedingung erfüllen (siehe verwandten Beitrag)
Notiz:Einige der letztgenannten Beispiele stammen aus PyCon von Víctor Terrón (sprechen) (Spanisch), „Kung Fu im Morgengrauen mit Itertools“.Siehe auch die groupby
Quellcode geschrieben in C.
Antwort
# OP: Yes, you can use `groupby`, e.g.
[do_something(list(g)) for _, g in groupby(lxml_elements, key=criteria_func)]
Ein anderes Beispiel:
for key, igroup in itertools.groupby(xrange(12), lambda x: x // 5):
print key, list(igroup)
ergibt
0 [0, 1, 2, 3, 4]
1 [5, 6, 7, 8, 9]
2 [10, 11]
Beachten Sie, dass igroup ein Iterator ist (ein Unteriterator, wie er in der Dokumentation genannt wird).
Dies ist nützlich, um einen Generator aufzuteilen:
def chunker(items, chunk_size):
'''Group items in chunks of chunk_size'''
for _key, group in itertools.groupby(enumerate(items), lambda x: x[0] // chunk_size):
yield (g[1] for g in group)
with open('file.txt') as fobj:
for chunk in chunker(fobj):
process(chunk)
Ein weiteres Beispiel für Groupby – wenn die Schlüssel nicht sortiert sind.Im folgenden Beispiel werden Elemente in xx nach Werten in yy gruppiert.In diesem Fall wird zuerst eine Menge von Nullen ausgegeben, gefolgt von einer Menge von Einsen, gefolgt von einer Menge von Nullen.
xx = range(10)
yy = [0, 0, 0, 1, 1, 1, 0, 0, 0, 0]
for group in itertools.groupby(iter(xx), lambda x: yy[x]):
print group[0], list(group[1])
Produziert:
0 [0, 1, 2]
1 [3, 4, 5]
0 [6, 7, 8, 9]
WARNUNG:
Die Syntax list(groupby(...)) funktioniert nicht wie gewünscht.Es scheint die internen Iteratorobjekte zu zerstören, also wird es verwendet
for x in list(groupby(range(10))):
print(list(x[1]))
wird herstellen:
[]
[]
[]
[]
[]
[]
[]
[]
[]
[9]
Versuchen Sie anstelle von list(groupby(...)) [(k, list(g)) für k,g in groupby(...)], oder wenn Sie diese Syntax häufig verwenden,
def groupbylist(*args, **kwargs):
return [(k, list(g)) for k, g in groupby(*args, **kwargs)]
und erhalten Sie Zugriff auf die Groupby-Funktionalität, während Sie gleichzeitig diese lästigen Iteratoren (für kleine Datenmengen) vermeiden.
Ich möchte ein weiteres Beispiel geben, bei dem Groupby ohne Sortierung nicht funktioniert.Nach einem Beispiel von James Sulak
from itertools import groupby
things = [("vehicle", "bear"), ("animal", "duck"), ("animal", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]
for key, group in groupby(things, lambda x: x[0]):
for thing in group:
print "A %s is a %s." % (thing[1], key)
print " "
Ausgabe ist
A bear is a vehicle.
A duck is a animal.
A cactus is a animal.
A speed boat is a vehicle.
A school bus is a vehicle.
Es gibt zwei Gruppen mit Fahrzeugen, wobei man nur eine Gruppe erwarten könnte
@CaptSolo, ich habe dein Beispiel ausprobiert, aber es hat nicht funktioniert.
from itertools import groupby
[(c,len(list(cs))) for c,cs in groupby('Pedro Manoel')]
Ausgabe:
[('P', 1), ('e', 1), ('d', 1), ('r', 1), ('o', 1), (' ', 1), ('M', 1), ('a', 1), ('n', 1), ('o', 1), ('e', 1), ('l', 1)]
Wie Sie sehen können, gibt es zwei „Os“ und zwei „E“, die jedoch in getrennte Gruppen eingeteilt wurden.Da wurde mir klar, dass Sie die an die Groupby-Funktion übergebene Liste sortieren müssen.Die korrekte Verwendung wäre also:
name = list('Pedro Manoel')
name.sort()
[(c,len(list(cs))) for c,cs in groupby(name)]
Ausgabe:
[(' ', 1), ('M', 1), ('P', 1), ('a', 1), ('d', 1), ('e', 2), ('l', 1), ('n', 1), ('o', 2), ('r', 1)]
Denken Sie daran: Wenn die Liste nicht sortiert ist, verwenden Sie die Groupby-Funktion wird nicht funktionieren!
Wie verwende ich Pythons itertools.groupby()?
Sie können Groupby verwenden, um Dinge zu gruppieren, über die iteriert werden soll.Sie geben Groupby eine iterierbare und eine optionale Schlüssel Funktion/Callable, mit der die Elemente überprüft werden, wenn sie aus der Iterable kommen, und sie gibt einen Iterator zurück, der ein Zwei-Tupel des Ergebnisses der Key-Callable und der tatsächlichen Elemente in einer anderen Iterable liefert.Aus der Hilfe:
groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).
Hier ist ein Beispiel für Groupby, bei dem eine Coroutine zum Gruppieren nach einer Anzahl verwendet wird. Dabei wird ein aufrufbarer Schlüssel verwendet (in diesem Fall coroutine.send
), um einfach die Anzahl für beliebig viele Iterationen und einen gruppierten Unteriterator von Elementen auszuspucken:
import itertools
def grouper(iterable, n):
def coroutine(n):
yield # queue up coroutine
for i in itertools.count():
for j in range(n):
yield i
groups = coroutine(n)
next(groups) # queue up coroutine
for c, objs in itertools.groupby(iterable, groups.send):
yield c, list(objs)
# or instead of materializing a list of objs, just:
# return itertools.groupby(iterable, groups.send)
list(grouper(range(10), 3))
druckt
[(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]
Sortieren und gruppieren
from itertools import groupby
val = [{'name': 'satyajit', 'address': 'btm', 'pin': 560076},
{'name': 'Mukul', 'address': 'Silk board', 'pin': 560078},
{'name': 'Preetam', 'address': 'btm', 'pin': 560076}]
for pin, list_data in groupby(sorted(val, key=lambda k: k['pin']),lambda x: x['pin']):
... print pin
... for rec in list_data:
... print rec
...
o/p:
560076
{'name': 'satyajit', 'pin': 560076, 'address': 'btm'}
{'name': 'Preetam', 'pin': 560076, 'address': 'btm'}
560078
{'name': 'Mukul', 'pin': 560078, 'address': 'Silk board'}
Ein nützliches Beispiel, das mir begegnet ist, könnte hilfreich sein:
from itertools import groupby
#user input
myinput = input()
#creating empty list to store output
myoutput = []
for k,g in groupby(myinput):
myoutput.append((len(list(g)),int(k)))
print(*myoutput)
Beispieleingabe:14445221
Beispielausgabe:(1,1) (3,4) (1,5) (2,2) (1,1)
Sie können eine eigene Groupby-Funktion schreiben:
def groupby(data):
kv = {}
for k,v in data:
if k not in kv:
kv[k]=[v]
else:
kv[k].append(v)
return kv
Run on ipython:
In [10]: data = [('a', 1), ('b',2),('a',2)]
In [11]: groupby(data)
Out[11]: {'a': [1, 2], 'b': [2]}