Domanda

Non sono riuscito a trovare una spiegazione comprensibile su come utilizzare effettivamente Python itertools.groupby() funzione.Quello che sto cercando di fare è questo:

  • Fai un elenco: in questo caso, i figli di un oggetto oggettivato lxml elemento
  • Dividilo in gruppi in base ad alcuni criteri
  • Quindi ripetere successivamente ciascuno di questi gruppi separatamente.

Ho rivisto la documentazione, E gli esempi, ma ho avuto difficoltà a provare ad applicarli oltre un semplice elenco di numeri.

Quindi, come lo utilizzo itertools.groupby()?C'è un'altra tecnica che dovrei usare?Sarebbero apprezzati anche suggerimenti per una buona lettura "prerequisita".

È stato utile?

Soluzione

NOTA IMPORTANTE: Si deve ordinare i tuoi dati Primo.


La parte che non ho capito è quella nella costruzione di esempio

groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
   groups.append(list(g))    # Store group iterator as a list
   uniquekeys.append(k)

k è la chiave di raggruppamento corrente e g è un iteratore che puoi utilizzare per scorrere il gruppo definito da quella chiave di raggruppamento.In altre parole, il groupby iterator stesso restituisce gli iteratori.

Eccone un esempio, utilizzando nomi di variabili più chiari:

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 " "

Questo ti darà l'output:

Un orso è un animale.
Un'anatra è un animale.

Un cactus è una pianta.

Una barca veloce è un veicolo.
Uno scuolabus è un veicolo.

In questo esempio, things è un elenco di tuple in cui il primo elemento di ciascuna tupla è il gruppo a cui appartiene il secondo elemento.

IL groupby() la funzione accetta due argomenti:(1) i dati da raggruppare e (2) la funzione con cui raggrupparli.

Qui, lambda x: x[0] racconta groupby() per utilizzare il primo elemento in ogni tupla come chiave di raggruppamento.

In quanto sopra for dichiarazione, groupby restituisce tre coppie (chiave, iteratore di gruppo), una volta per ciascuna chiave univoca.È possibile utilizzare l'iteratore restituito per scorrere ogni singolo elemento in quel gruppo.

Ecco un esempio leggermente diverso con gli stessi dati, utilizzando una comprensione dell'elenco:

for key, group in groupby(things, lambda x: x[0]):
    listOfThings = " and ".join([thing[1] for thing in group])
    print key + "s:  " + listOfThings + "."

Questo ti darà l'output:

animali:orso e anatra.
impianti:cactus.
veicoli:motoscafo e scuolabus.

Altri suggerimenti

Puoi mostrarci il tuo codice?

L'esempio sui documenti Python è abbastanza semplice:

groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
    groups.append(list(g))      # Store group iterator as a list
    uniquekeys.append(k)

Quindi nel tuo caso, i dati sono un elenco di nodi, keyfunc è dove va la logica della funzione dei criteri e poi groupby() raggruppa i dati.

Devi stare attento a ordinare i dati secondo i criteri prima di chiamare groupby oppure non funzionerà. groupby Il metodo in realtà scorre semplicemente un elenco e ogni volta che la chiave cambia crea un nuovo gruppo.

Un bel trucco con groupby è eseguire la codifica della lunghezza in una riga:

[(c,len(list(cgen))) for c,cgen in groupby(some_string)]

ti fornirà un elenco di tuple doppie in cui il primo elemento è il carattere e il secondo è il numero di ripetizioni.

Modificare:Nota che questo è ciò che separa itertools.groupby dall'SQL GROUP BY semantica:itertools non (e in generale non può) ordinare l'iteratore in anticipo, quindi i gruppi con la stessa "chiave" non vengono uniti.

itertools.groupby è uno strumento per raggruppare elementi.

Da i documenti, otteniamo ulteriori informazioni su cosa potrebbe fare:

# [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 gli oggetti producono coppie di gruppi chiave in cui il gruppo è un generatore.

Caratteristiche

  • UN.Raggruppa elementi consecutivi
  • B.Raggruppa tutte le occorrenze di un elemento, dato un iterabile ordinato
  • C.Specificare come raggruppare gli elementi con una funzione chiave

Confronti

# 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']

Usi

Nota:Molti di questi ultimi esempi derivano da PyCon di Víctor Terrón (parlare) (Spagnolo), "Kung Fu all'alba con Itertools".Vedi anche il groupbycodice sorgente scritto in c.


Risposta

# OP: Yes, you can use `groupby`, e.g. 
[do_something(list(g)) for _, g in groupby(lxml_elements, key=criteria_func)]

Un altro esempio:

for key, igroup in itertools.groupby(xrange(12), lambda x: x // 5):
    print key, list(igroup)

risultati in

0 [0, 1, 2, 3, 4]
1 [5, 6, 7, 8, 9]
2 [10, 11]

Tieni presente che igroup è un iteratore (un sottoiteratore come lo chiama la documentazione).

Questo è utile per dividere in blocchi un generatore:

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)

Un altro esempio di groupby: quando le chiavi non sono ordinate.Nell'esempio seguente, gli elementi in xx sono raggruppati in base ai valori in yy.In questo caso viene emessa prima una serie di zeri, seguita da una serie di unità e infine da una serie di zeri.

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])

Produce:

0 [0, 1, 2]
1 [3, 4, 5]
0 [6, 7, 8, 9]

AVVERTIMENTO:

La sintassi list(groupby(...)) non funzionerà nel modo previsto.Sembra distruggere gli oggetti iteratori interni, quindi utilizzando

for x in list(groupby(range(10))):
    print(list(x[1]))

produrrà:

[]
[]
[]
[]
[]
[]
[]
[]
[]
[9]

Invece di list(groupby(...)), prova [(k, list(g)) for k,g in groupby(...)], o se usi spesso quella sintassi,

def groupbylist(*args, **kwargs):
    return [(k, list(g)) for k, g in groupby(*args, **kwargs)]

e accedi alla funzionalità groupby evitando tutti insieme quei fastidiosi iteratori (per piccoli dati).

Vorrei fornire un altro esempio in cui il groupby senza ordinamento non funziona.Adattato dall'esempio di 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 " "

l'uscita è

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.

i gruppi con veicolo sono due, mentre ci si potrebbe aspettare un solo gruppo

@CaptSolo, ho provato il tuo esempio, ma non ha funzionato.

from itertools import groupby 
[(c,len(list(cs))) for c,cs in groupby('Pedro Manoel')]

Produzione:

[('P', 1), ('e', 1), ('d', 1), ('r', 1), ('o', 1), (' ', 1), ('M', 1), ('a', 1), ('n', 1), ('o', 1), ('e', 1), ('l', 1)]

Come puoi vedere, ci sono due o e due e, ma sono divise in gruppi separati.È stato allora che ho capito che devi ordinare l'elenco passato alla funzione groupby.Quindi, l'utilizzo corretto sarebbe:

name = list('Pedro Manoel')
name.sort()
[(c,len(list(cs))) for c,cs in groupby(name)]

Produzione:

[(' ', 1), ('M', 1), ('P', 1), ('a', 1), ('d', 1), ('e', 2), ('l', 1), ('n', 1), ('o', 2), ('r', 1)]

Basta ricordare, se la lista non è ordinata, la funzione groupby non funzionerà!

Come utilizzo itertools.groupby() di Python?

Puoi utilizzare groupby per raggruppare elementi su cui eseguire l'iterazione.Dai a groupby un iterabile e un facoltativo chiave function/callable con cui controllare gli elementi non appena escono dall'iterabile e restituisce un iteratore che fornisce una doppia tupla del risultato della chiave richiamabile e degli elementi effettivi in ​​un altro iterabile.Dall'aiuto:

groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).

Ecco un esempio di groupby utilizzando una coroutine per raggruppare in base a un conteggio, utilizza una chiave richiamabile (in questo caso, coroutine.send) per sputare semplicemente il conteggio per quante iterazioni e un sub-iteratore raggruppato di elementi:

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))

stampe

[(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]

Ordinamento e raggruppamento

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'}

Un esempio utile che ho trovato potrebbe essere utile:

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)

Esempio di input:14445221

Output di esempio:(1,1) (3,4) (1,5) (2,2) (1,1)

Puoi scrivere la tua funzione groupby:

           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]}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top