
En Python, vous pouvez regrouper des éléments consécutifs de même valeur dans un objet itérable tel qu’une liste avec itertools.groupby().
import itertools
l = [0, 0, 0, 1, 1, 2, 0, 0]
print([(k, list(g)) for k, g in itertools.groupby(l)])
# [(0, [0, 0, 0]), (1, [1, 1]), (2, [2]), (0, [0, 0])]
Cet article décrit le contenu suivant.
- Comment utiliser itertools.groupby()
- Spécifiez une fonction calculant une valeur clé pour chaque élément :
key - Agréger comme GROUP BY en SQL
- Pour les tuples et les chaînes
Utilisez collections.Counter pour compter le nombre d’éléments de même valeur, quel que soit leur ordre, c’est-à-dire consécutifs ou non consécutifs.
itertools.groupby() renvoie un itérateur de clés et de groupes. Les valeurs ne sont pas imprimées par print().
l = [0, 0, 0, 1, 1, 2, 0, 0]
print(itertools.groupby(l))
#
Le groupe renvoyé est également un itérateur. Par exemple, utilisez list() pour créer une liste.
Le groupe retourné est lui-même un itérateur qui partage l’itérable sous-jacent avec groupby(). Comme la source est partagée, lorsque l’objet groupby() est avancé, le groupe précédent n’est plus visible. Donc, si ces données sont nécessaires plus tard, elles doivent être stockées sous forme de liste :
itertools.groupby() — Fonctions créant des itérateurs pour une boucle efficace — Documentation Python 3.10.4
for k, g in itertools.groupby(l):
print(k, g)
# 0
# 1
# 2
# 0
for k, g in itertools.groupby(l):
print(k, list(g))
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2]
# 0 [0, 0]
Vous pouvez utiliser les compréhensions de liste pour obtenir une liste de clés uniquement, de groupes uniquement ou des deux (tuples de clé et de groupe).
print([k for k, g in itertools.groupby(l)])
# [0, 1, 2, 0]
print([list(g) for k, g in itertools.groupby(l)])
# [[0, 0, 0], [1, 1], [2], [0, 0]]
print([(k, list(g)) for k, g in itertools.groupby(l)])
# [(0, [0, 0, 0]), (1, [1, 1]), (2, [2]), (0, [0, 0])]
Spécifiez une fonction calculant une valeur clé pour chaque élément :key
Vous pouvez spécifier le paramètre clé pour itertools.groupby(). L’utilisation de key est la même que pour d’autres fonctions telles que sorted(), max(), min(), etc.
Sur la base du résultat de la fonction (objet appelable) spécifié dans la clé, il est déterminé si les valeurs des éléments consécutifs sont les mêmes.
Par exemple, si vous spécifiez la fonction intégrée len(), qui renvoie la longueur (nombre de caractères) d’une chaîne, les éléments de même longueur sont regroupés. Les parenthèses () ne sont pas nécessaires lors de la spécification de la clé.
l = ['aaa', 'bbb', 'ccc', 'a', 'b', 'aa', 'bb']
print([(k, list(g)) for k, g in itertools.groupby(l, len)])
# [(3, ['aaa', 'bbb', 'ccc']), (1, ['a', 'b']), (2, ['aa', 'bb'])]
Déterminez si le nombre est pair ou impair avec une expression lambda :
l = [0, 2, 0, 3, 1, 4, 4, 0]
print([(k, list(g)) for k, g in itertools.groupby(l, lambda x: x % 2)])
# [(0, [0, 2, 0]), (1, [3, 1]), (0, [4, 4, 0])]
Agréger comme GROUP BY en SQL
Vous pouvez regrouper des données bidimensionnelles (telles qu’une liste de listes) en fonction d’une colonne donnée, comme GROUP BY en SQL, avec clé.
Ici, une expression lambda est utilisée pour obtenir l’élément à la position souhaitée dans la liste, mais operator.itemgetter() peut également être utilisé.
De plus, l’instruction for est utilisée pour faciliter la lecture de la sortie, mais bien sûr, vous pouvez également utiliser des compréhensions de liste comme dans les exemples précédents.
l = [[0, 'Alice', 0],
[1, 'Alice', 10],
[2, 'Bob', 20],
[3, 'Bob', 30],
[4, 'Alice', 40]]
for k, g in itertools.groupby(l, lambda x: x[1]):
print(k, list(g))
# Alice [[0, 'Alice', 0], [1, 'Alice', 10]]
# Bob [[2, 'Bob', 20], [3, 'Bob', 30]]
# Alice [[4, 'Alice', 40]]
Avec itertools.groupby(), seuls les éléments consécutifs de même valeur sont regroupés. Pour les regrouper quel que soit leur ordre, triez la liste d’origine avec sorted().
Lors du tri d’une liste de listes, par défaut, la liste est triée par le premier élément de chaque liste. Pour trier par élément à la position donnée, spécifiez le paramètre clé de sorted().
for k, g in itertools.groupby(sorted(l, key=lambda x: x[1]), lambda x: x[1]):
print(k, list(g))
# Alice [[0, 'Alice', 0], [1, 'Alice', 10], [4, 'Alice', 40]]
# Bob [[2, 'Bob', 20], [3, 'Bob', 30]]
Additionnez les nombres avec une expression génératrice :
for k, g in itertools.groupby(sorted(l, key=lambda x: x[1]), lambda x: x[1]):
print(k, sum(x[2] for x in g))
# Alice 50
# Bob 50
Notez que pandas a également groupby() pour le regroupement et l’agrégation. Pandas est plus pratique pour gérer des données complexes.
Pour les tuples et les chaînes
Vous pouvez utiliser itertools.groupby() pour gérer non seulement des listes mais aussi des tuples, des chaînes, etc.
Pour les tuples :
t = (0, 0, 0, 1, 1, 2, 0, 0)
print([(k, list(g)) for k, g in itertools.groupby(t)])
# [(0, [0, 0, 0]), (1, [1, 1]), (2, [2]), (0, [0, 0])]
Utilisez tuple() si vous voulez faire d’un groupe un tuple au lieu d’une liste.
print(tuple((k, tuple(g)) for k, g in itertools.groupby(t)))
# ((0, (0, 0, 0)), (1, (1, 1)), (2, (2,)), (0, (0, 0)))
Pour les chaînes :
s = 'aaabbcaa'
print([(k, list(g)) for k, g in itertools.groupby(s)])
# [('a', ['a', 'a', 'a']), ('b', ['b', 'b']), ('c', ['c']), ('a', ['a', 'a'])]
Utilisez join() si vous voulez transformer un groupe en chaîne.
print([(k, ''.join(g)) for k, g in itertools.groupby(s)])
# [('a', 'aaa'), ('b', 'bb'), ('c', 'c'), ('a', 'aa')]
Bien sûr, vous pouvez également gérer tout autre objet itérable avec itertools.groupby().
