web-dev-qa-db-fra.com

Liste des groupes par valeurs

Disons que j'ai une liste comme celle-ci:

list = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]

Comment puis-je le grouper le plus élégamment pour obtenir cette sortie de liste en Python:

list = [["A", "C"], ["B"], ["D", "E"]]

Les valeurs sont donc regroupées par valeur secondaire mais l'ordre est préservé ...

50
Veles
values = set(map(lambda x:x[1], list))
newlist = [[y[0] for y in list if y[1]==x] for x in values]
81
Howard
from operator import itemgetter
from itertools import groupby

lki = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
lki.sort(key=itemgetter(1))

glo = [[x for x,y in g]
       for k,g in  groupby(lki,key=itemgetter(1))]

print glo

.

MODIFIER

Une autre solution qui ne nécessite aucune importation, est plus lisible, conserve les commandes et est 22% moins longue que la précédente:

oldlist = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]

newlist, dicpos = [],{}
for val,k in oldlist:
    if k in dicpos:
        newlist[dicpos[k]].extend(val)
    else:
        newlist.append([val])
        dicpos[k] = len(dicpos)

print newlist
27
eyquem

La réponse d'Howard est concise et élégante, mais c'est aussi O (n ^ 2) dans le pire des cas. Pour les grandes listes contenant un grand nombre de valeurs de clé de regroupement, vous devez d'abord trier la liste, puis utiliser itertools.groupby:

>>> from itertools import groupby
>>> from operator import itemgetter
>>> seq = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
>>> seq.sort(key = itemgetter(1))
>>> groups = groupby(seq, itemgetter(1))
>>> [[item[0] for item in data] for (key, data) in groups]
[['A', 'C'], ['B'], ['D', 'E']]

Modifier:

J'ai changé cela après avoir vu la réponse d'Eyequem: itemgetter(1) est plus agréable que lambda x: x[1].

20
Robert Rossney
>>> import collections
>>> D1 = collections.defaultdict(list)
>>> for element in L1:
...     D1[element[1]].append(element[0])
... 
>>> L2 = D1.values()
>>> print L2
[['A', 'C'], ['B'], ['D', 'E']]
>>> 
7
DTing

Je ne connais pas l'élégance, mais c'est certainement faisable:

oldlist = [["A",0], ["B",1], ["C",0], ["D",2], ["E",2]]
# change into: list = [["A", "C"], ["B"], ["D", "E"]]

order=[]
dic=dict()
for value,key in oldlist:
  try:
    dic[key].append(value)
  except KeyError:
    order.append(key)
    dic[key]=[value]
newlist=map(dic.get, order)

print newlist

Cela préserve l'ordre de la première occurrence de chaque clé, ainsi que l'ordre des éléments pour chaque clé. Il nécessite que la clé soit lavable, mais ne lui attribue pas autrement de sens.

2
Yann Vernier
len = max(key for (item, key) in list)
newlist = [[] for i in range(len+1)]
for item,key in list:
  newlist[key].append(item)

Vous pouvez le faire dans une seule liste de compréhension, peut-être plus élégante mais O (n ** 2):

[[item for (item,key) in list if key==i] for i in range(max(key for (item,key) in list)+1)]
1
sverre