Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a Pythonic way of doing the following transformation on a list of dicts?

I have a list of dicts like this:

l = [{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}] 

and I would like to obtain an output of this form:

>>> [('foo', 'bar'), ([1,2,3,4], [5,6,7,8])] 

But short of for-looping and appending I don't see a solution. Is there a smarter way than doing this?

names = [] values = [] for d in l:     names.append(d['name'])     values.append(d['values']) 
like image 440
oarfish Avatar asked Oct 29 '18 13:10

oarfish


People also ask

What is Pythonic?

In short, “pythonic” describes a coding style that leverages Python's unique features to write code that is readable and beautiful. To help us better understand, let's briefly look at some aspects of the Python language.

What are dictionary and list comprehensions in Python?

List comprehensions and dictionary comprehensions are a powerful substitute to for-loops and also lambda functions. Not only do list and dictionary comprehensions make code more concise and easier to read, they are also faster than traditional for-loops.


2 Answers

Use generator expression:

l = [{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}] v = [tuple(k["name"] for k in l), tuple(k["values"] for k in l)] print(v) 

Output:

[('foo', 'bar'), ([1, 2, 3, 4], [5, 6, 7, 8])] 
like image 176
eyllanesc Avatar answered Sep 20 '22 00:09

eyllanesc


I would use a list comprehension (much like eyllanesc's) if I was writing this code for public consumption. But just for fun, here's a one-liner that doesn't use any fors.

>>> l = [{'name': 'foo', 'values': [1,2,3,4]}, {'name': 'bar', 'values': [5,6,7,8]}] >>> list(zip(*map(dict.values, l))) [('foo', 'bar'), ([1, 2, 3, 4], [5, 6, 7, 8])] 

(Note that this only reliably works if dictionaries preserve insertion order, which is not the case in all versions of Python. CPython 3.6 does it as an implementation detail, but it is only guaranteed behavior as of 3.7.)

Quick breakdown of the process:

  • dict.values returns a dict_values object, which is an iterable containing all the values of the dict.
  • map takes each dictionary in l and calls dict.values on it, returning an iterable of dict_values objects.
  • zip(*thing) is a classic "transposition" recipe, which takes an iterable-of-iterables and effectively flips it diagonally. E.g. [[a,b],[c,d]] becomes [[a,c], [b,d]]. This puts all the names into one tuple, and all the values into another.
  • list converts the zip object into a list.
like image 36
Kevin Avatar answered Sep 20 '22 00:09

Kevin