Question

Je n'ai pas réussi à trouver une explication compréhensible sur la façon d'utiliser réellement Python. itertools.groupby() fonction.Ce que j'essaie de faire, c'est ceci :

  • Faites une liste - dans ce cas, les enfants d'un enfant 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 révisé La documentation, et les exemples, mais j'ai eu du mal à essayer de les appliquer au-delà d'une simple liste de chiffres.

Alors, comment puis-je utiliser itertools.groupby()?Y a-t-il une autre technique que je devrais utiliser ?Des indications vers de bonnes lectures « préalables » seraient également appréciées.

Était-ce utile?

La solution

NOTE IMPORTANTE: Vous devez trier vos données d'abord.


La partie que je n'ai pas comprise, c'est que dans 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)

k est la clé de regroupement actuelle, et g est un itérateur que vous pouvez utiliser pour parcourir le groupe défini par cette clé de regroupement.En d'autres termes, le groupby l'itérateur lui-même renvoie les itérateurs.

En voici un exemple, 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 bateau rapide est un véhicule.
Un autobus scolaire est un véhicule.

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

Le groupby() la fonction prend deux arguments :(1) les données à regrouper et (2) la fonction avec laquelle les regrouper.

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

Au dessus for déclaration, groupby renvoie 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:bateau rapide et bus scolaire.

Autres conseils

Peux-tu nous montrer ton 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, puis groupby() regroupe les données.

Vous devez faire attention à trier les données par les critères avant d'appeler groupby ou ça ne marchera pas. groupby en fait, la méthode parcourt simplement une liste et chaque fois que la clé change, elle crée un nouveau groupe.

Une astuce intéressante avec groupby consiste à exécuter le codage de longueur sur une seule 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.

Modifier:Notez que c'est ce qui sépare itertools.groupby du SQL GROUP BY sémantique:itertools ne trie pas (et en général ne peut pas) l'itérateur à l'avance, donc les groupes avec la même "clé" ne sont pas fusionnés.

itertools.groupby est un outil pour regrouper des éléments.

Depuis les documents, nous glanons plus loin ce que cela 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

groupby les objets génèrent des paires de groupes-clés où le groupe est un générateur.

Caractéristiques

  • UN.Regrouper les éléments consécutifs
  • B.Regrouper toutes les occurrences d'un élément, à partir d'un itérable trié
  • C.Spécifier 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

Note:Plusieurs de ces derniers exemples proviennent du PyCon de Víctor Terrón (parler) (Espagnol), "Kung Fu à l'aube avec Itertools".Voir aussi le groupbycode 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)]

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 segmenter 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 valeurs dans 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]

AVERTISSEMENT:

La syntaxe list(groupby(...)) ne fonctionnera pas comme vous le souhaitez.Il semble détruire les objets itérateurs internes, 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 tous ces itérateurs embêtants (pour les petites données).

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

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

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

Sortir:

[('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 répartis dans des groupes distincts.C'est à ce moment-là que j'ai réalisé qu'il fallait trier la liste passée à la fonction groupby.L'utilisation correcte serait donc :

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

Sortir:

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

N'oubliez pas que si la liste n'est pas triée, la fonction groupby ne fonctionnera pas!

Comment utiliser itertools.groupby() de Python ?

Vous pouvez utiliser groupby pour regrouper les éléments sur lesquels parcourir.Vous donnez à groupby un itérable et un facultatif clé fonction/callable par laquelle vérifier les éléments à mesure qu'ils sortent de l'itérable, et il renvoie un itérateur qui donne un double du résultat de la clé appelable et des éléments réels dans un autre itérable.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 regrouper par nombre, elle utilise une clé appelable (dans ce cas, coroutine.send) pour simplement cracher le décompte pour 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])]

Tri et regroupement

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 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 de saisie :14445221

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

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]}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top