use - itertools python documentation




Como uso o itertools.groupby()? (8)

Não consegui encontrar uma explicação compreensível de como realmente usar a função itertools.groupby() do Python. O que estou tentando fazer é o seguinte:

  • Faça uma lista - nesse caso, os filhos de um elemento lxml objetivado
  • Divida-o em grupos com base em alguns critérios
  • Depois, repita cada um desses grupos separadamente.

Analisei a documentação e os exemplos , mas tive problemas ao tentar aplicá-los além de uma simples lista de números.

Então, como uso o itertools.groupby() ? Existe outra técnica que eu deveria estar usando? Indicadores para uma boa leitura de "pré-requisito" também serão apreciados.


Classificação e agrupamento

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

Como uso o itertools.groupby () do Python?

Você pode usar groupby para agrupar coisas para repetir. Você atribui ao grupo uma iterável e uma função- chave opcional / que pode ser chamada pela qual verificar os itens à medida que eles saem do iterável, e ele retorna um iterador que fornece duas tuplas do resultado da chave que pode ser chamada e dos itens reais em outro iterável. Da ajuda:

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

Aqui está um exemplo de groupby usando uma corotina para agrupar por uma contagem, ele usa uma chave que pode ser chamada (neste caso, coroutine.send ) para cuspir a contagem para quantas iterações e um sub-iterador 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))

impressões

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

ATENÇÃO:

A lista de sintaxe (groupby (...)) não funcionará da maneira que você pretende. Parece destruir os objetos do iterador interno, portanto, usando

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

vai produzir:

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

Em vez de list (groupby (...)), tente [(k, list (g)) para k, g em groupby (...)] ou, se você usa essa sintaxe com frequência,

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

e obtenha acesso à funcionalidade groupby, evitando os iteradores irritantes (para pequenos dados) todos juntos.


Eu gostaria de dar outro exemplo em que groupby sem classificação não está funcionando. Adaptado do exemplo por 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 " "

saída é

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.

existem dois grupos com veículo, enquanto um poderia esperar apenas um grupo


Um exemplo útil que me deparei pode ser ú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 amostra: 14445221

Resultado da amostra: (1,1) (3,4) (1,5) (2,2) (1,1)


Um truque neato com groupby é executar a codificação de comprimento em uma linha:

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

fornecerá uma lista de duas tuplas em que o primeiro elemento é o caractere e o segundo é o número de repetições.

Edit: Observe que é isso que separa itertools.groupby da semântica do SQL GROUP BY : itertools não (e geralmente não pode) classificar o iterador antecipadamente, para que grupos com a mesma "chave" não sejam mesclados.


Você pode nos mostrar seu código?

O exemplo nos documentos do Python é bastante direto:

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

Portanto, no seu caso, dados são uma lista de nós, keyfunc é o local onde a lógica da função de critérios vai e, em seguida, groupby() agrupa os dados.

Você deve ter o cuidado de classificar os dados de acordo com os critérios antes de ligar para groupby ou eles não funcionarão. groupby método groupby na verdade apenas percorre uma lista e, sempre que a chave é alterada, ele cria um novo grupo.


itertools.groupby é uma ferramenta para agrupar itens.

A partir dos documentos , analisamos ainda mais o que isso pode fazer:

# [k for k, g in groupby('AAAABBBCCDAABBB')] --> ABCDAB

# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D

groupby objetos groupby produzem pares de grupos de chaves em que o grupo é um gerador.

Recursos

  • A. Agrupe itens consecutivos
  • B. Agrupe todas as ocorrências de um item, considerando uma iterável classificada
  • C. Especifique como agrupar itens com uma função de tecla *

Comparações

# Define a printer for comparing outputs
>>> def print_groupby(iterable, keyfunc=None):
...    for k, g in it.groupby(iterable, keyfunc):
...        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
>>> # keyfunc = lambda s: s.islower()                      # equivalent
>>> def keyfunc(s):
...     """Return a True if a string is lowercase, else False."""   
...     return s.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), keyfunc)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']

Usos

Nota: Vários dos últimos exemplos derivam do PyCon de Víctor Terrón (talk) (Spanish) , "Kung Fu ao amanhecer com ferramentas". Veja também o código-fonte do grupo escrito em C.

* Uma função na qual todos os itens são passados ​​e comparados, influenciando o resultado. Outros objetos com funções principais incluem sorted() , max() e min() .

Resposta

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




iteration