Python Générateur d'Expression pour l'Accumulation de Dictionnaire des Valeurs
Un générateur d'expression est en train de jeter à côté d'un grand nombre de tuple paires par exemple. sous forme de liste:
pairs = [(3, 47), (6, 47), (9, 47), (6, 27), (11, 27), (23, 27), (41, 27), (4, 67), (9, 67), (11, 67), (33, 67)]
Pour chaque paire en paire avec key = paire[0] et la valeur = paire[1], je veux nourrir ce flux de paires dans un dictionnaire de cumulativement ajouter les valeurs pour les touches correspondantes. La solution la plus évidente est:
dict_k_v = {}
for pair in pairs:
try:
dict_k_v[pair[0]] += pair[1]
except:
dict_k_v[pair[0]] = pair[1]
>>> dict_k_v
{33: 67, 3: 47, 4: 67, 6: 74, 9: 114, 11: 94, 41: 27, 23: 27}
Toutefois, cela pourrait être réalisé avec un générateur d'expression ou d'une même construction que ne pas utiliser une boucle for?
MODIFIER
Pour clarifier, le générateur d'expression est en train de jeter à côté d'un grand nombre de tuple paires:
(3, 47), (6, 47), (9, 47), (6, 27), (11, 27), (23, 27), (41, 27), (4, 67), (9, 67), (11, 67), (33, 67) ...
et je veux accumuler chaque paire clé-valeur dans un dictionnaire (voir Paul McGuire réponse) que chaque paire est généré. Les paires = liste[] déclaration est inutile et désolé à ce sujet. Pour chaque paire (x,y), x est un entier et y peuvent être un nombre entier ou décimal/float.
Mon générateur d'expression est de la forme:
((x,y) for y in something() for x in somethingelse())
et pour accumuler chaque (x,y) de la paire dans un defaultdict. Hth.
- Qu'est-ce que cette aversion pour les boucles dernièrement? Une boucle enroulée autour d'une accumulation dans un defaultdict est la solution la plus propre.
- J'ai juste eu une longue discussion à propos de toutes les options pour pousser dans un dict et il s'avère que le moyen le plus efficace pour le code c'est avec des si la clé dans le dict: / autre: (non pas que vous vouliez utiliser une boucle for 🙂
- Le premier aversion pour les boucles le risque de dégradation des performances lorsque les ensembles de données sont très importantes et/ou de l'exécution de l'opération continuellement. Une option est Cython, mais je voudrais voir si il y a un Python solution qui utilise les fonctions intégrées.
- Dans sa réponse, Paul McGuire ajoute explicitement à la question de ce que j'avais supposé évident (oups!) c'est à dire. "... accepter chaque paire clé-valeur qui lui sont envoyées, et de les accumuler dans un defaultdict passés dans celui-ci". J'ai ajouté ceci à la question d'origine.
Vous devez vous connecter pour publier un commentaire.
De discussion, ici est un simple générateur de fonction pour nous donner quelques données:
Et voici la solution de base qui utilise un Python pour la boucle de consommer le générateur et représenter les nombres pour chaque paire clé-valeur
Impression sera quelque chose comme:
Mais nous pouvons créer une coroutine qui va accepter de chaque paire clé-valeur qui lui sont envoyées, et de les accumuler dans un defaultdict passés dans celui-ci:
Nous allons initialiser la coroutine avec un pointage defaultdict, et qu'elle soit prête à accepter les valeurs par l'envoi d'une valeur None à elle:
Nous pourrions utiliser une boucle for ou une compréhension de liste pour envoyer toutes les générateur de valeurs de la coroutine:
ou
Mais au lieu de cela, nous allons utiliser une taille zéro deque pour traiter tout le générateur d'expression de valeurs sans créer temporaires inutiles de la liste d'Aucun de:
Maintenant nous regardons les valeurs de nouveau:
Et on a une liste semblable à la première:
Lire plus à propos de coroutines à David Beazley page: http://www.dabeaz.com/coroutines/
for x,y in itertools.product(something(), somethingelse())
Si vous voulez juste pour lier les valeurs retournées par les deux fonctions, utilisez zip au lieu de produit. Notez également que somethingelse() est appelée à y fois - vous ne savez pas si le produit est assez intelligent pour éviter cela ou pas.Vous pouvez utiliser un tuple déstructuration et une
defaultdict
de raccourcir la boucle de beaucoup de choses:Ce encore utilise une boucle for, mais vous n'avez pas à gérer le cas où la clé n'a pas été vu avant. Je pense que c'est probablement la meilleure solution, à la fois la lisibilité et de performance.
La preuve de concept à l'aide de
groupby
Cela dit, vous pourrait faire à l'aide de
itertools.groupby
, mais c'est un peu un hack:Aussi, cela devrait en fait être moins performant que la première approche, parce que en mémoire une liste de toutes les paires doit être créé pour le tri.
for
-boucle d'autant mieux.sorted
comparaison lexicographiquement par défaut?sorted
's way.Non, vous ne pouvez pas le faire sans l'aide de certains forme de boucle. Et à l'aide d'un
for
boucle est vraiment la chose la plus sensée, parce que vous êtes en train de modifier quelque chose dans le corps de la boucle (et non pas, par exemple, la création d'un nouvel objet iterable ou de la liste.) Néanmoins, vous pouvez simplifier le code en utilisant uncollections.defaultdict
, comme suit:Haskell a un très beau générique d'assistance pour ceci:
Data.Map
'sfromListWith
.fromListWith
est similaire à Pythondict
les constructeurs, mais il accepte aussi un supplément de combinant la fonction de combiner répétée les touches de valeurs. De le traduire en Python:À l'aide de cette aide, il est facile d'exprimer une multitude de combinaisons:
Noter que, contrairement aux solutions à l'aide de
defaultdict(int)
, cette approche n'est pas limitée à des valeurs numériques, comme en témoigne la liste exemple ci-dessus. (En général, tout monoïde est un utile: il se définit avec l'union/intersection, les booléens et, ou, des chaînes de caractères avec la concaténation, et ainsi de suite.)Additif:
Comme d'autres commentaires l'a souligné, il n'y a rien de mal avec l'aide d'une boucle pour cela: c'est le faible niveau de la solution. Cependant, il est toujours bon si vous pouvez envelopper le faible niveau de code réutilisables, de plus haut niveau d'abstraction.
Vous pouvez mettre en place un appel récursif, cependant Python n'est pas optimisé pour la récursion sur la queue de sorte que vous devrez payer une pénalité sur la vitesse et ont le potentiel d'une "récurrence" profondes exception.
Je voudrais mettre en œuvre dans une boucle for:
pourquoi ne voulez-vous pas utiliser une boucle for?
Quelque chose comme: