Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transposing (pivoting) a dict of lists in python [duplicate]

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.

like image 1000
Bilentor Avatar asked May 27 '16 17:05

Bilentor


People also ask

How to transpose a list of list of lists in Python?

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.

How to transpose elements of two dimensional list in Python?

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.

How to transpose 2D list in Python (swap rows and columns)?

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 ()

How to create a dictionary of lists in Python?

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.


3 Answers

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}]
like image 151
Martijn Pieters Avatar answered Nov 15 '22 22:11

Martijn Pieters


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)
like image 32
mgilson Avatar answered Nov 15 '22 20:11

mgilson


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.

like image 32
user2290820 Avatar answered Nov 15 '22 21:11

user2290820