web-dev-qa-db-fra.com

Comment grouper une liste de tuples / objets par index / attribut similaire en python?

Étant donné une liste

old_list = [obj_1, obj_2, obj_3, ...]

Je veux créer une liste:

new_list = [[obj_1, obj_2], [obj_3], ...]

obj_1.some_attr == obj_2.some_attr.

Je pourrais lancer des boucles for et des contrôles if ensemble, mais c'est moche. Existe-t-il un moyen Pythonique pour cela? au fait, les attributs des objets sont tous des chaînes.

Alternativement, une solution pour une liste contenant des tuples (de la même longueur) au lieu d'objets est également appréciée.

33
Aufwind

defaultdict est la façon dont cela se fait.

Alors que les boucles for sont largement essentielles, les instructions if ne le sont pas.

from collections import defaultdict


groups = defaultdict(list)

for obj in old_list:
    groups[obj.some_attr].append(obj)

new_list = groups.values()
43
S.Lott

Voici deux cas. Les deux nécessitent les importations suivantes:

import itertools
import operator

Vous utiliserez itertools.groupby et operator.attrgetter ou operator.itemgetter .

Pour une situation où vous regroupez par obj_1.some_attr == obj_2.some_attr:

get_attr = operator.attrgetter('some_attr')
new_list = [list(g) for k, g in itertools.groupby(sorted(old_list, key=get_attr), get_attr)]

Pour a[some_index] == b[some_index]:

get_item = operator.itemgetter(some_index)
new_list = [list(g) for k, g in itertools.groupby(sorted(old_list, key=get_item), get_item)]

Notez que vous avez besoin du tri car itertools.groupby crée un nouveau groupe lorsque la valeur de la clé change.


Notez que vous pouvez l'utiliser pour créer un dict comme la réponse de S.Lott, mais ne devez pas utiliser collections.defaultdict.

Utiliser une compréhension de dictionnaire (ne fonctionne qu'avec Python 3+, et éventuellement Python 2.7 mais je ne suis pas sûr)):

groupdict = {k: g for k, g in itertools.groupby(sorted_list, keyfunction)}

Pour les versions précédentes de Python, ou comme alternative plus succincte:

groupdict = dict(itertools.groupby(sorted_list, keyfunction))
24
JAB

Pensez que vous pouvez également essayer d'utiliser itertools.groupby . Veuillez noter que le code ci-dessous n'est qu'un exemple et doit être modifié en fonction de vos besoins:

data = [[1,2,3],[3,2,3],[1,1,1],[7,8,9],[7,7,9]]

from itertools import groupby

# for example if you need to get data grouped by each third element you can use the following code
res = [list(v) for l,v in groupby(sorted(data, key=lambda x:x[2]), lambda x: x[2])]# use third element for grouping
13
Artsiom Rudzenka