following o开发者_Go百科n from this question
i have the following lists in python which i want to recombine into a dictionary/list:
from
fromfruits = { "names" : ['banana','grapefruit','apple'] , "colors" : ['yellow','pink','green'], ... }
to
tofruits = [
{'name':'banana','color':'yellow',...},
{'name':'grapefruit','color':'pink',...},
{'name':'apple','color':'green',...}
]
what's the best way to do it so that i can have n properties listed in fromfruits?
please help! :)
Since the request is now to be more general:
>>> 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'}]
since the order of keys
and values
are the same (assuming no intervening modifications to the dictionary).
It'd be pretty hard to go from keys like 'names' to 'name', teaching the program how to do proper english singlularization ... so i renamed the keys in the input:
ff = dict(name=['banana','grapefruit','apple'], color=['yellow','pink','green'],
yummy=[True,False,True])
You can solve this problem with zip
again:
# 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'}, ... ]
[dict((x, fromfruits[x][n]) for x in fromfruits.keys())
for n in range(len(next(fromfruits.itervalues())))]
Optimize as desired.
>>> 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'}]
And now in some more detail (re-formatted for clarity):
>>>[{'name': name, 'color': color}
for name in fromfruits['names']
for color in fromfruits['colors']]
This is a "list comprehension" with a double for
which goes over all combinations of names and colors. You can add a third loop if you want to mix in other attributes, like "shape" or whatever.
not very pythonic, but ...
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]
This problem is a bit more convoluted than the average list comprehension because of the nested dictionaries.
However if you can create the right iterable then a list comprehension is the way to go.
Try:
tofruits = [ {'name':n, 'color':c} for n,c in zip(fromfruits['names'],
fromfruits['colors']) ]
Here the zip
function is used to produce tuples which match the correct name
and color
. This is a good way to go here because both are stored in basic lists within the fromfruits
dict.
These tuples (from zip
) are then unpacked into n
and c
, which are then used as in a typical list comprehension.
精彩评论