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.

War es hilfreich?

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

Notiz:Einige der letztgenannten Beispiele stammen aus PyCon von Víctor Terrón (sprechen) (Spanisch), „Kung Fu im Morgengrauen mit Itertools“.Siehe auch die groupbyQuellcode 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]}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top