Reputation: 47705
Imagine I have these python lists:
keys = ['name', 'age']
values = ['Monty', 42, 'Matt', 28, 'Frank', 33]
Is there a direct or at least a simple way to produce the following list of dictionaries ?
[
{'name': 'Monty', 'age': 42},
{'name': 'Matt', 'age': 28},
{'name': 'Frank', 'age': 33}
]
Upvotes: 6
Views: 2138
Reputation: 54544
In the answer by Konrad Rudolph
zip nearly does what you want; unfortunately, rather than cycling the shorter list, it breaks. Perhaps there's a related function that cycles?
Here's a way:
keys = ['name', 'age']
values = ['Monty', 42, 'Matt', 28, 'Frank', 33]
iter_values = iter(values)
[dict(zip(keys, iter_values)) for _ in range(len(values) // len(keys))]
I will not call it Pythonic (I think it's too clever), but it might be what are looking for.
There is no benefit in cycling the keys
list using itertools
.cycle()
, because each traversal of keys
corresponds to the creation of one dictionnary.
EDIT: Here's another way:
def iter_cut(seq, size):
for i in range(len(seq) / size):
yield seq[i*size:(i+1)*size]
keys = ['name', 'age']
values = ['Monty', 42, 'Matt', 28, 'Frank', 33]
[dict(zip(keys, some_values)) for some_values in iter_cut(values, len(keys))]
This is much more pythonic: there's a readable utility function with a clear purpose, and the rest of the code flows naturally from it.
Upvotes: 2
Reputation: 7512
Here is the zip way
def mapper(keys, values):
n = len(keys)
return [dict(zip(keys, values[i:i + n]))
for i in range(0, len(values), n)]
Upvotes: 14
Reputation: 1452
[dict(zip(keys,values[n:n+len(keys)])) for n in xrange(0,len(values),len(keys)) ]
UG-LEEE. I'd hate to see code that looks like that. But it looks right.
def dictizer(keys, values):
steps = xrange(0,len(values),len(keys))
bites = ( values[n:n+len(keys)] for n in steps)
return ( dict(zip(keys,bite)) for bite in bites )
Still a little ugly, but the names help make sense of it.
Upvotes: 0
Reputation: 546183
zip
nearly does what you want; unfortunately, rather than cycling the shorter list, it breaks. Perhaps there's a related function that cycles?
$ python
>>> keys = ['name', 'age']
>>> values = ['Monty', 42, 'Matt', 28, 'Frank', 33]
>>> dict(zip(keys, values))
{'age': 42, 'name': 'Monty'}
/EDIT: Oh, you want a list of dict. The following works (thanks to Peter, as well):
from itertoos import cycle
keys = ['name', 'age']
values = ['Monty', 42, 'Matt', 28, 'Frank', 33]
x = zip(cycle(keys), values)
map(lambda a: dict(a), zip(x[::2], x[1::2]))
Upvotes: 2
Reputation: 14505
It's not pretty but here's a one-liner using a list comprehension, zip and stepping:
[dict(zip(keys, a)) for a in zip(values[::2], values[1::2])]
Upvotes: 3
Reputation: 25463
Dumb way, but one that comes immediately to my mind:
def fields_from_list(keys, values):
iterator = iter(values)
while True:
yield dict((key, iterator.next()) for key in keys)
list(fields_from_list(keys, values)) # to produce a list.
Upvotes: 2
Reputation: 25463
Yet another try, perhaps dumber than the first one:
def split_seq(seq, count):
i = iter(seq)
while True:
yield [i.next() for _ in xrange(count)]
>>> [dict(zip(keys, rec)) for rec in split_seq(values, len(keys))]
[{'age': 42, 'name': 'Monty'},
{'age': 28, 'name': 'Matt'},
{'age': 33, 'name': 'Frank'}]
But it's up to you to decide whether it's dumber.
Upvotes: 1
Reputation: 18084
Here's my simple approach. It seems to be close to the idea that @Cheery had except that I destroy the input list.
def pack(keys, values):
"""This function destructively creates a list of dictionaries from the input lists."""
retval = []
while values:
d = {}
for x in keys:
d[x] = values.pop(0)
retval.append(d)
return retval
Upvotes: 1