I have a dictionary that looks like:
{'x': [1, 2, 3], 'y': [4, 5, 6]}
I want to transform it to the following format:
[{'x': 1, 'y': 4}, {'x': 2, 'y': 5}, {'x': 3, 'y': 6}]
I can do it by explicit loops but is there a good pythonic way to do it?
Edit: Turns out there is a similar question here and one of the answers is same as the accepted answer here but the author of that answer writes "I do not condone the use of such code in any kind of real system". Can someone explain why such code is bad? It appears very elegant to me.
Given a two-dimensional list of integers, write a Python program to get the transpose of given list of lists. In Python, a matrix can be interpreted as a list of lists. Each element is treated as a row of the matrix.
Python | Transpose elements of two dimensional list. 1 Python. def transpose (l1, l2): for i in range(len(l1 [0])): row =[] for item in l1: row.append (item [i]) l2.append (row) return l2. l1 = [ [4, 5, 3, ... 2 Python. 3 Python3. 4 Python.
Transpose 2D list in Python (swap rows and columns) 1 Convert to numpy.ndarray and transpose with T 2 Convert to pandas.DataFrame and transpose with T 3 Transpose with built-in function zip ()
Let’s see all the different ways we can create a dictionary of Lists. Method #2: Adding nested list as value using append () method. Create a new list and we can simply append that list to the value. Iterate the list and keep appending the elements till given range using setdefault () method.
Use zip()
a few times, counting on the fact that both dict.items()
and iteration directly over a dict
return elements in the same order as long as the dictionary is not mutated in between:
[dict(zip(d, col)) for col in zip(*d.values())]
The zip(*d.values())
call transposes the list values, and the zip(d, col)
call pairs up each column with the keys in the dictionary again.
The above is the equivalent of spelling out the keys manually:
[dict(zip(('x', 'y'), col)) for col in zip(d['x'], d['y'])]
without having to spell out the keys manually.
Demo:
>>> d = {'x': [1, 2, 3], 'y': [4, 5, 6]}
>>> [dict(zip(d, col)) for col in zip(*d.values())]
[{'x': 1, 'y': 4}, {'x': 2, 'y': 5}, {'x': 3, 'y': 6}]
I don't think there is any easy to read, pithy 1-liner for this (though it's probably not hard to come up with a difficult to read, pithy 1-liner ... ;) -- at least not in the general case (arbitrary number of dict items where the keys are unknown).
If you know the keys of the dict, I think it's probably easiest to work with that (especially since there are only 2 of them in the example).
Build the new dicts in 2 passes. The first pass fills in x
, the second pass fills in y
.
new_dicts = [{'x': x} for x in d['x']]
for new_dict, y in zip(new_dicts, d['y']):
new_dict['y'] = y
If you'd rather do it in 1 pass, I think this isn't too bad either:
new_dicts = [{'x': x, 'y': y} for x, y in zip(d['x'], d['y'])]
If you have a list of keys, I might do it slightly differently ...
import operator
value_getter = operator.itemgetter(*list_of_keys)
new_dicts_values = zip(*value_getter(d))
new_dicts = [
dict(zip(list_of_keys, new_dict_values))
for new_dict_values in new_dicts_values]
This is pretty much the same strategy taken in Martijn's answer ... However, I think that breaking it out a little and giving things names helps make it a little more clear what is going on. Also, this takes away the mental overhead of having to convince yourself that zipping an unordered dict
with an unordered list of column values is OK since they're unordered in the same way...
And, of course, if you don't actually have a list of keys, you can always get one by
list_of_keys = list(d)
if
d = {'x': [1, 2, 3], 'y': [4, 5, 6]}
One could try:
keys = d.keys()
print map(lambda tupl: map(lambda k,v: {k:v}, keys, tupl), zip(*d.itervalues()))
Looks pythonic but for larger entries the overhead of lambda calls each time map calls lambda function, will increase.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With