2010-11-03 10 views
1

suite à this questionrecombiner une liste/dictionnaire en python

i ont les listes suivantes en python que je veux recombiner dans un dictionnaire/liste:

de

fromfruits = { "names" : ['banana','grapefruit','apple'] , "colors" : ['yellow','pink','green'], ... } 

à

tofruits = [ 
{'name':'banana','color':'yellow',...}, 
{'name':'grapefruit','color':'pink',...}, 
{'name':'apple','color':'green',...} 
] 

quelle est la meilleure façon de le faire afin que je puisse avoir n propriétés énumérés dans fromfruits?

aidez s'il vous plaît! :)

+0

Le premier bit de code n'est pas valide Python. Voulez-vous dire 'fromfruits = {" noms ": [" banane "," pamplemousse ", ...]," couleurs ": [...], ...}'? –

+0

désolé oui - ont corrigé. – significance

+0

Je pense que la question n'est pas assez claire. Voulez-vous toutes les combinaisons de couleurs pour tous les noms, ou autre chose? [voir différentes réponses ci-dessous] –

Répondre

4

Depuis la demande est maintenant plus générale:

>>> from itertools import izip 
>>> ff = {'colors': ['yellow', 'pink', 'green'], 'names': ['banana', 'grapefruit', 'apple'], 'blah': ['a','b','c']} 

>>> [dict(izip(ff.iterkeys(), v)) for v in izip(*ff.itervalues())] 
[{'blah': 'a', 'colors': 'yellow', 'names': 'banana'}, 
{'blah': 'b', 'colors': 'pink', 'names': 'grapefruit'}, 
{'blah': 'c', 'colors': 'green', 'names': 'apple'}] 

depuis l'ordre de keys et values sont les mêmes (en supposant l'absence d'intervention modifications au dictionnaire).

+0

Je pense que le but de cette question est de ne plus mentionner les noms ('colors', 'names') mais d'autoriser un nombre inconnu de noms. Sinon, ce serait à peu près la même chose que sa dernière question. –

+0

Donc, la couleur est «banane» et le nom est «jaune»? Qu'est-ce qui ne va pas avec cette image? – hughdbrown

+0

@hugh: ha ha, bonne prise. –

0
>>> fromfruits 
{'colors': ['yellow', 'pink', 'green'], 'names': ['banana', 'grapefruit', 'apple']} 
>>> [{'name': name, 'color': color} for name in fromfruits['names'] for color in fromfruits['colors']] 
[{'color': 'yellow', 'name': 'banana'}, {'color': 'pink', 'name': 'banana'}, {'color': 'green', 'name': 'banana'}, {'color': 'yellow', 'name': 'grapefruit'}, {'color': 'pink', 'name': 'grapefruit'}, {'color': 'green', 'name': 'grapefruit'}, {'color': 'yellow', 'name': 'apple'}, {'color': 'pink', 'name': 'apple'}, {'color': 'green', 'name': 'apple'}] 

Et maintenant un peu plus en détail (re-formaté pour plus de clarté):

>>>[{'name': name, 'color': color} 
     for name in fromfruits['names'] 
     for color in fromfruits['colors']] 

C'est une « compréhension de la liste » avec un double for qui passe au-dessus de toutes les combinaisons de noms et couleurs . Vous pouvez ajouter une troisième boucle si vous voulez mélanger d'autres attributs, comme "shape" ou autre.

+2

Je ne pense pas que les bananes soient supposées être roses et vertes. –

+0

@Seth: Je suis d'accord, mais je considère cela comme un simple échantillon de données que l'OP pensait, pas une tentative de guerre biologique ;-) –

+0

Je pense que le problème (par opposition à la question précédente liée à l'OP) est que le nombre de propriétés est variable - il peut y avoir plus que simplement 'name' et' color'. Aussi, il ne cherche pas un produit cartésien de noms de fruits et de couleurs, il essaie de remodeler la structure. –

0

pas très pythonique, mais ...

keys = fromfruits.keys() 
nvals = len(fromfruits[keys[0]]) 
tofruits = [ ] 
for i in range(nvals): 
    tofruits.append ({ }) 
    for k in keys: 
     tofruits[-1][k] = fromfruits[k][i] 
1
[dict((x, fromfruits[x][n]) for x in fromfruits.keys()) 
    for n in range(len(next(fromfruits.itervalues())))] 

Optimiser comme vous le souhaitez.

3

Il serait assez difficile de passer de clés comme « noms » à « nom », l'enseignement du programme comment faire singlularization bon anglais ... donc je renomme les clés de l'entrée:

ff = dict(name=['banana','grapefruit','apple'], color=['yellow','pink','green'], 
      yummy=[True,False,True]) 

Vous pouvez résoudre ce problème avec zip à nouveau:

# make fruits [('yellow', True, 'banana'), ('pink', False, 'grapefruit'), ... ] 
fruits = zip(*ff.itervalues()) 

# then add the names to each fruit 
tofruits = [dict(zip(ff.iterkeys(),fruit)) for fruit in fruits] 
# gives: [{'color': 'yellow', 'yummy': True, 'name': 'banana'}, ... ] 
0

ce problème est un peu plus compliqué que la compréhension de la liste moyenne en raison des dictionnaires imbriqués.

Cependant si vous pouvez créer le bon itérable alors une liste de compréhension est la voie à suivre.

Essayez:

tofruits = [ {'name':n, 'color':c} for n,c in zip(fromfruits['names'], 
               fromfruits['colors']) ] 

Ici, la fonction zip est utilisée pour produire tuples qui correspondent à la name et color correcte. C'est un bon moyen d'aller ici parce que les deux sont stockés dans des listes de base au sein de la fromfruits dict.

Ces tuples (de zip) sont ensuite décompressés en n et c, qui sont ensuite utilisés comme dans une liste typique.