Pregunta

No he podido encontrar una explicación comprensible de cómo utilizar realmente Python. itertools.groupby() función.Lo que estoy tratando de hacer es esto:

  • Tome una lista: en este caso, los hijos de una persona objetivada. lxml elemento
  • Dividirlo en grupos según algunos criterios.
  • Luego, repita cada uno de estos grupos por separado.

he revisado la documentación, y los ejemplos, pero he tenido problemas al intentar aplicarlos más allá de una simple lista de números.

Entonces, ¿cómo uso itertools.groupby()?¿Hay otra técnica que debería utilizar?También se agradecerían sugerencias sobre una buena lectura como "requisito previo".

¿Fue útil?

Solución

NOTA IMPORTANTE: Tienes que ordena tus datos primero.


La parte que no entendí es que en la construcción del ejemplo.

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

k es la clave de agrupación actual, y g es un iterador que puede utilizar para iterar sobre el grupo definido por esa clave de agrupación.En otras palabras, el groupby El propio iterador devuelve iteradores.

Aquí hay un ejemplo de eso, usando nombres de variables más claros:

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

Esto le dará el resultado:

Un oso es un animal.
Un pato es un animal.

Un cactus es una planta.

Una lancha rápida es un vehículo.
Un autobús escolar es un vehículo.

En este ejemplo, things es una lista de tuplas donde el primer elemento de cada tupla es el grupo al que pertenece el segundo elemento.

El groupby() La función toma dos argumentos:(1) los datos a agrupar y (2) la función con la que agruparlos.

Aquí, lambda x: x[0] dice groupby() para utilizar el primer elemento de cada tupla como clave de agrupación.

en lo anterior for declaración, groupby devuelve tres pares (clave, iterador de grupo), una vez para cada clave única.Puede utilizar el iterador devuelto para iterar sobre cada elemento individual de ese grupo.

Aquí hay un ejemplo ligeramente diferente con los mismos datos, usando una lista por comprensión:

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

Esto le dará el resultado:

animales:oso y pato.
plantas:cactus.
vehículos:lancha rápida y autobús escolar.

Otros consejos

¿Puedes mostrarnos tu código?

El ejemplo de los documentos de Python es bastante sencillo:

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

Entonces, en su caso, los datos son una lista de nodos, keyfunc es donde va la lógica de su función de criterios y luego groupby() agrupa los datos.

Debes tener cuidado de ordenar los datos por los criterios antes de llamar groupby o no funcionará. groupby El método en realidad simplemente recorre una lista y cada vez que cambia la clave, crea un nuevo grupo.

Un buen truco con groupby es ejecutar la codificación de longitud en una línea:

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

le dará una lista de 2 tuplas donde el primer elemento es el carácter y el segundo es el número de repeticiones.

Editar:Tenga en cuenta que esto es lo que separa itertools.groupby del SQL GROUP BY semántica:itertools no ordena (y en general no puede) el iterador por adelantado, por lo que los grupos con la misma "clave" no se fusionan.

itertools.groupby es una herramienta para agrupar elementos.

De los documentos, recogemos más a fondo lo que podría hacer:

# [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 Los objetos producen pares clave-grupo donde el grupo es un generador.

Características

  • A.Agrupar elementos consecutivos
  • B.Agrupar todas las apariciones de un elemento, dado un iterable ordenado
  • C.Especificar cómo agrupar elementos con una función clave

Comparaciones

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

Usos

Nota:Varios de estos últimos ejemplos derivan del PyCon de Víctor Terrón. (hablar) (Español), "Kung Fu al amanecer con Itertools".Ver también el groupbycódigo fuente escrito en c.


Respuesta

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

Otro ejemplo:

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

resultados en

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

Tenga en cuenta que igroup es un iterador (un subiterador como lo llama la documentación).

Esto es útil para fragmentar un generador:

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)

Otro ejemplo de agrupación: cuando las claves no están ordenadas.En el siguiente ejemplo, los elementos de xx se agrupan por valores en yy.En este caso, primero se genera un conjunto de ceros, seguido de un conjunto de unos y seguido nuevamente de un conjunto de ceros.

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]

ADVERTENCIA:

La sintaxis list(groupby(...)) no funcionará de la forma deseada.Parece destruir los objetos iteradores internos, por lo que usar

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

Producirá:

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

En lugar de list(groupby(...)), pruebe [(k, list(g)) for k,g in groupby(...)], o si usa esa sintaxis con frecuencia,

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

y obtenga acceso a la funcionalidad groupby evitando por completo esos molestos iteradores (para datos pequeños).

Me gustaría dar otro ejemplo en el que groupby sin clasificación no funciona.Adaptado del ejemplo de 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 " "

la salida es

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.

Hay dos grupos con vehículo, mientras que se podría esperar un solo grupo.

@CaptSolo, probé tu ejemplo, pero no funcionó.

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

Producción:

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

Como puedes ver, hay dos o y dos e, pero se ubicaron en grupos separados.Fue entonces cuando me di cuenta de que necesitabas ordenar la lista pasada a la función groupby.Entonces el uso correcto sería:

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

Producción:

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

Solo recordando, si la lista no está ordenada, la función groupby no trabajará!

¿Cómo uso itertools.groupby() de Python?

Puedes usar groupby para agrupar cosas sobre las que iterar.Le das a groupby un iterable y un opcional. llave función/invocable mediante la cual verificar los elementos a medida que salen del iterable, y devuelve un iterador que da una doble tupla del resultado de la clave invocable y los elementos reales en otro iterable.De la ayuda:

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

A continuación se muestra un ejemplo de groupby que utiliza una rutina para agrupar por un recuento; utiliza una clave invocable (en este caso, coroutine.send) para simplemente escupir el recuento de cuantas iteraciones y un subiterador agrupado de elementos:

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

huellas dactilares

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

Ordenar y agrupar

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 ejemplo útil que encontré puede resultar útil:

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)

Entrada de muestra:14445221

Salida de muestra:(1,1) (3,4) (1,5) (2,2) (1,1)

Puedes escribir tu propia función 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]}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top