use Como eu uso o itertools.groupby() do Python?




itertools python documentation (10)

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

  • Pegue uma lista - nesse caso, os filhos de um elemento lxml objetivado
  • Divida-o em grupos com base em alguns critérios
  • Em seguida, faça uma iteração sobre cada um desses grupos separadamente.

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

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


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)

Exemplo de entrada: 14445221

Potência da amostra: (1,1) (3,4) (1,5) (2,2) (1,1)


Eu gostaria de dar outro exemplo em que groupby sem ordenaçã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


AVISO:

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

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

vai produzir:

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

Em vez disso, da lista (groupby (...)), tente [(k, list (g)) para k, g em groupby (...)], ou se você usar essa sintaxe frequentemente,

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

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


Você pode escrever a própria função 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]}

@CaptSolo, eu tentei o seu exemplo, mas não funcionou.

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

Saída:

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

Como você pode ver, há dois o e dois e, mas eles entraram em grupos separados. Foi quando percebi que você precisa classificar a lista passada para a função groupby. Então, o uso correto seria:

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

Saída:

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

Apenas lembrando, se a lista não estiver classificada, a função groupby não funcionará !


Como eu uso o itertools.groupby () do Python?

Você pode usar o groupby para agrupar coisas para iterar. Você dá ao groupby um iterável, e uma função- chave opcional / selecionável pela qual verificar os itens conforme eles saem do iterável, e retorna um iterador que dá uma dupla tupla do resultado da chave callable e os 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 co-rotina 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])]

NOTA IMPORTANTE: você tem que classificar seus dados primeiro.

A parte que eu não entendi é que na construção de exemplo

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

k é a chave de agrupamento atual e g é um iterador que você pode usar para iterar sobre o grupo definido por essa chave de agrupamento. Em outras palavras, o próprio iterador groupby retorna iteradores.

Aqui está um exemplo disso, usando nomes de variáveis ​​mais 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 " "

Isso lhe dará a saída:

Um urso é um animal.
Um pato é um animal.

Um cacto é uma planta.

Uma lancha é um veículo.
Um ônibus escolar é um veículo.

Neste exemplo, as things são uma lista de tuplas onde o primeiro item em cada tupla é o grupo ao qual o segundo item pertence.

A função groupby() recebe dois argumentos: (1) os dados para agrupar e (2) a função para agrupá-los.

Aqui, lambda x: x[0] diz ao groupby() para usar o primeiro item em cada tupla como chave de agrupamento.

No exemplo acima, groupby retorna três pares (chave, grupo iterador) - uma vez para cada chave única. Você pode usar o iterador retornado para iterar sobre cada item individual desse grupo.

Aqui está um exemplo ligeiramente diferente com os mesmos dados, usando uma compreensão da lista:

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

Isso lhe dará a saída:

animais: urso e pato.
plantas: cactus.
veículos: lancha e ônibus escolar.


itertools.groupby é uma ferramenta para agrupar itens.

A partir dos documentos , podemos ver melhor o que poderia fazer:

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

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

groupby objetos groupby geram pares de grupos-chave onde o grupo é um gerador.

Características

  • A. Agrupar itens consecutivos juntos
  • B. Agrupar todas as ocorrências de um item, dado um iterável ordenado
  • C. Especifique como agrupar itens com uma função-chave

Comparações

# 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: Vários dos últimos exemplos derivam de PyCon de Víctor Terrón (talk) (Spanish) , "Kung Fu at Dawn with Itertools". Veja também o código-fonte groupby escrito em C.

Resposta

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

Ordenar e groupby

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

Outro exemplo:

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

resulta em

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

Note que o grupo é um iterador (um sub-iterador como a documentação o chama).

Isso é útil para dividir um gerador:

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)

Outro exemplo de groupby - quando as chaves não são classificadas. No exemplo a seguir, os itens em xx são agrupados por valores em yy. Nesse caso, um conjunto de zeros é gerado primeiro, seguido por um conjunto de zeros, seguido novamente por um conjunto de zeros.

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

Produz:

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




iteration