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

  • A+

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']) 


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.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: