Supposons que j'ai un ensemble de paires de données où l' index 0 est la valeur et l' index 1 est le type:
input = [
('11013331', 'KAT'),
('9085267', 'NOT'),
('5238761', 'ETH'),
('5349618', 'ETH'),
('11788544', 'NOT'),
('962142', 'ETH'),
('7795297', 'ETH'),
('7341464', 'ETH'),
('9843236', 'KAT'),
('5594916', 'ETH'),
('1550003', 'ETH')
]
Je souhaite les regrouper par leur type (par la 1ère chaîne indexée) comme tel:
result = [
{
type:'KAT',
items: ['11013331', '9843236']
},
{
type:'NOT',
items: ['9085267', '11788544']
},
{
type:'ETH',
items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003']
}
]
Comment puis-je y parvenir de manière efficace?
[('11013331', 'red', 'KAT'), ('9085267', 'blue' 'KAT')]
où le dernier élément du tuple est la clé et les deux premiers comme valeur. Le résultat devrait ressembler à ceci: result = [{type: 'KAT', items: [('11013331', red), ('9085267', blue)]}]from operator import itemgetter
d= {}; for k,v in input: d.setdefault(k, []).append(v)
Le
itertools
module intégré de Python a en fait unegroupby
fonction, mais pour cela les éléments à grouper doivent d'abord être triés de telle sorte que les éléments à grouper soient contigus dans la liste:Maintenant, l'entrée ressemble à:
groupby
renvoie une séquence de 2-tuples, de la forme(key, values_iterator)
. Ce que nous voulons, c'est transformer cela en une liste de dictionnaires où le 'type' est la clé, et 'items' est une liste des 0 'éléments des tuples retournés par le values_iterator. Comme ça:result
Contient maintenant votre dict souhaité, comme indiqué dans votre question.Vous pouvez cependant envisager de créer un seul dict à partir de cela, indexé par type, et chaque valeur contenant la liste de valeurs. Dans votre formulaire actuel, pour trouver les valeurs d'un type particulier, vous devrez parcourir la liste pour trouver le dict contenant la clé 'type' correspondante, puis en extraire l'élément 'items'. Si vous utilisez un seul dict au lieu d'une liste de dictés à 1 élément, vous pouvez trouver les éléments d'un type particulier avec une seule recherche à clé dans le dict maître. En utilisant
groupby
, cela ressemblerait à:result
contient maintenant ce dict (c'est similaire aures
defaultdict intermédiaire dans la réponse de @ KennyTM):(Si vous souhaitez réduire cela à une seule ligne, vous pouvez:
ou en utilisant le nouveau formulaire de compréhension de dict:
la source
J'ai aussi aimé le regroupement simple des pandas . il est puissant, simple et le plus adéquat pour les grands ensembles de données
result = pandas.DataFrame(input).groupby(1).groups
la source
Cette réponse est similaire à la réponse de @ PaulMcG mais ne nécessite pas de trier l'entrée.
Pour ceux qui s'intéressent à la programmation fonctionnelle,
groupBy
peut être écrit sur une seule ligne (sans compter les importations!), Et contrairement àitertools.groupby
cela, il ne nécessite pas le tri des entrées:(La raison
... or grp
enlambda
est que pour celareduce()
au travail, leslambda
besoins de retourner son premier argument, parce quelist.append()
toujours retourneNone
leor
sera toujours revenirgrp
. Ie c'est un hack pour contourner la restriction de python qu'un lambda ne peut évaluer une expression unique.)Cela renvoie un dict dont les clés sont trouvées en évaluant la fonction donnée et dont les valeurs sont une liste des éléments d'origine dans l'ordre d'origine. Pour l'exemple de l'OP, appeler ceci comme
groupBy(lambda pair: pair[1], input)
retournera ce dict:Et selon la réponse de @ PaulMcG, le format demandé par l'OP peut être trouvé en l'enveloppant dans une compréhension de liste. Alors ça va le faire:
la source
La fonction suivante regroupera rapidement ( aucun tri requis) des tuples de n'importe quelle longueur par une clé ayant n'importe quel index:
Dans le cas de votre question, l'index de la clé que vous souhaitez regrouper est 1, donc:
donne
qui n'est pas exactement le résultat que vous avez demandé, mais qui pourrait tout aussi bien répondre à vos besoins.
la source
la source