iteration - Comment utiliser itertools.groupby () de Python?

Translate

Je n'ai pas été en mesure de trouver une explication compréhensible sur la façon d'utiliser réellement Pythonitertools.groupby()fonction. Voici ce que j'essaye de faire:

  • Prenez une liste - dans ce cas, les enfants d'un objectivélxmlélément
  • Divisez-le en groupes en fonction de certains critères
  • Ensuite, parcourez chacun de ces groupes séparément.

J'ai revuLa documentation, etles exemples, mais j'ai eu du mal à les appliquer au-delà d'une simple liste de nombres.

Alors, comment utiliseritertools.groupby()? Y a-t-il une autre technique que je devrais utiliser? Des pointeurs vers une bonne lecture «préalable» seraient également appréciés.

This question and all comments follow the "Attribution Required."

Toutes les réponses

Translate

NOTE IMPORTANTE:Vous deveztrier vos donnéespremière.


La partie que je n'ai pas obtenue est celle de l'exemple de construction

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

kest la clé de regroupement actuelle, etgest un itérateur que vous pouvez utiliser pour parcourir le groupe défini par cette clé de regroupement. En d'autres termes, legroupbyiterator lui-même renvoie des itérateurs.

Voici un exemple de cela, en utilisant des noms de variables plus clairs:

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

Cela vous donnera le résultat:

Un ours est un animal.
Un canard est un animal.

Un cactus est une plante.

Un hors-bord est un véhicule.
Un autobus scolaire est un véhicule.

Dans cet exemple,thingsest une liste de tuples où le premier élément de chaque tuple est le groupe auquel appartient le deuxième élément.

legroupby()function prend deux arguments: (1) les données à grouper et (2) la fonction avec laquelle les grouper.

Ici,lambda x: x[0]racontegroupby()pour utiliser le premier élément de chaque tuple comme clé de regroupement.

Au dessusfordéclaration,groupbyrenvoie trois paires (clé, itérateur de groupe) - une fois pour chaque clé unique. Vous pouvez utiliser l'itérateur renvoyé pour parcourir chaque élément individuel de ce groupe.

Voici un exemple légèrement différent avec les mêmes données, en utilisant une compréhension de liste:

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

Cela vous donnera le résultat:

animaux: ours et canard.
plantes: cactus.
véhicules: hors-bord et autobus scolaire.

La source
Seb
Translate

Pouvez-vous nous montrer votre code?

L'exemple sur la documentation Python est assez simple:

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

Donc, dans votre cas, les données sont une liste de nœuds, keyfunc est l'endroit où va la logique de votre fonction de critères, puisgroupby()regroupe les données.

Vous devez faire attention àtrier les donnéespar les critères avant d'appelergroupbyou cela ne fonctionnera pas.groupbyEn fait, la méthode itère simplement dans une liste et chaque fois que la clé change, elle crée un nouveau groupe.

La source
Translate

itertools.groupbyest un outil de regroupement d'éléments.

Deles docs, nous glanons plus loin ce qu'il pourrait faire:

# [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

groupbyles objets génèrent des paires clé-groupe où le groupe est un générateur.

traits

  • A. Regrouper les éléments consécutifs
  • B. Regrouper toutes les occurrences d'un élément, à partir d'un itérable trié
  • C. Spécifiez comment regrouper les éléments avec une fonction clé

Comparaisons

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

Les usages

Remarque: plusieurs de ces derniers exemples proviennent du PyCon de Víctor Terrón(parler) (Espagnol), "Kung Fu à l'aube avec Itertools". Voir aussi legroupbycode sourceécrit en C.


Réponse

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

Une astuce intéressante avec groupby est d'exécuter le codage de longueur sur une ligne:

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

vous donnera une liste de 2 tuples où le premier élément est le caractère et le 2ème est le nombre de répétitions.

Edit: Notez que c'est ce qui sépareitertools.groupbydu SQLGROUP BYsémantique: itertools ne trie pas (et en général ne peut pas) trier l'itérateur à l'avance, donc les groupes avec la même «clé» ne sont pas fusionnés.

La source
Translate

Un autre exemple:

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

résulte en

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

Notez qu'igroup est un itérateur (un sous-itérateur comme l'appelle la documentation).

Ceci est utile pour découper un générateur:

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 autre exemple de groupby - lorsque les clés ne sont pas triées. Dans l'exemple suivant, les éléments de xx sont regroupés par des valeurs de yy. Dans ce cas, un ensemble de zéros est émis en premier, suivi d'un ensemble de uns, suivi à nouveau d'un ensemble de zéros.

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

Produit:

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

ATTENTION:

La liste de syntaxe (groupby (...)) ne fonctionnera pas comme vous le souhaitez. Il semble détruire les objets de l'itérateur interne, donc en utilisant

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

produira:

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

Au lieu de list (groupby (...)), essayez [(k, list (g)) for k, g in groupby (...)], ou si vous utilisez souvent cette syntaxe,

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

et accédez à la fonctionnalité groupby tout en évitant ces itérateurs embêtants (pour les petites données) tous ensemble.

La source
Translate

Je voudrais donner un autre exemple où groupby sans tri ne fonctionne pas. Adapté de l'exemple 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 sortie est

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.

il y a deux groupes avec véhicule, alors qu'on pourrait s'attendre à un seul groupe

La source
Translate

@CaptSolo, j'ai essayé votre exemple, mais cela n'a pas fonctionné.

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

Production:

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

Comme vous pouvez le voir, il y a deux o et deux e, mais ils sont entrés dans des groupes séparés. C'est là que j'ai réalisé que vous deviez trier la liste transmise à la fonction groupby. Ainsi, l'utilisation correcte serait:

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

Production:

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

Rappelez-vous simplement que si la liste n'est pas triée, la fonction groupbyne fonctionnera pas!

La source
Translate

Comment utiliser itertools.groupby () de Python?

Vous pouvez utiliser groupby pour regrouper les éléments à parcourir. Vous donnez à groupby un itérable et un facultatifcléfunction / callable pour vérifier les éléments à mesure qu'ils sortent de l'itérable, et il retourne un itérateur qui donne un deux-tuple du résultat de la clé appelable et des éléments réels dans un autre iterable. De l'aide:

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

Voici un exemple de groupby utilisant une coroutine pour grouper par un nombre, il utilise une touche appelable (dans ce cas,coroutine.send) pour cracher simplement le nombre d'itérations et un sous-itérateur groupé d'éléments:

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

impressions

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

Tri et 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'}
La source
Translate

Un exemple utile que j'ai rencontré peut être 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)

Exemple d'entrée: 14445221

Exemple de sortie: (1,1) (3,4) (1,5) (2,2) (1,1)

La source
Translate

Vous pouvez écrire votre propre fonction 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]}
La source