Python – Flatten a dict of lists into unique values?
Question:
I have a dict of lists in python:
content = {88962: [80, 130], 87484: [64], 53662: [58,80]}
I want to turn it into a list of the unique values
[58,64,80,130]
I wrote a manual solution, but it’s a manual solution. I know there are more concise and more elegant way to do this with list comprehensions, map/reduce , itertools , etc. anyone have a clue ?
content = {88962: [80, 130], 87484: [64], 53662: [58,80]}
result = set({})
for k in content.keys() :
for i in content[k]:
result.add(i)
# and list/sort/print just to compare the output
r2 = list( result )
r2.sort()
print r2
Answers:
use set()
and itertools.chain()
:
In [83]: content = {88962: [80, 130], 87484: [64], 53662: [58,80]}
In [84]: from itertools import chain
In [94]: x=set(chain(*content.values()))
In [95]: x
Out[95]: set([58, 64, 80, 130]) # a set, the items may or may not be sorted
In [96]: sorted(x) #convert set to a sorted list
Out[96]: [58, 64, 80, 130]
sorted(set(val
for row in content.itervalues()
for val in row))
set
gets us all the distinct values (like a dictionary, but without the overhead of storing values). sorted
then just takes the created set
and returns a list
sorted in ascending order.
list(reduce(lambda a, b: a.union(set(b)), content.itervalues(), set()))
The lambda
turns the two input arguments into sets and unions them.
The reduce
will do a left fold over the list that is passed to it — in this case, the lists that are the values of your dictionaries.
The reduce
will turn the result of this, which is a set
back into a list.
This can also be spelled:
list(reduce(lambda a, b: a | set(b), content.itervalues(), set()))
In python3.7 you can use a combination of .values
, and chain
.
from itertools import chain
sorted(set(chain(*content.values())))
# [58, 64, 80, 130]
# another option is `itertools.groupby`
from itertools import groupby
[k for k, g in groupby(sorted(chain(*content.values())))]
In python2.7
from itertools import chain
sorted(set(chain.from_iterable(content.itervalues())))
# [58, 64, 80, 130]
# another option is `itertools.groupby`
[k for k, g in groupby(sorted(chain.from_iterable(content.itervalues())))]
Double set comprehension:
Python 3:
sorted({x for v in content.values() for x in v})
Python 2:
sorted({x for v in content.itervalues() for x in v})
sorted(set(sum(content.values(), [])))
Use list comprehension to generate a non-unique list, convert it to a set to get the unique values, and then back into a sorted list. Perhaps not the most efficient, but yet another one line solution (this time with no imports).
Python 3:
sorted(list(set([val for vals in content.values() for val in vals])))
Python 2.7:
sorted(list(set([val for vals in content.itervalues() for val in vals])))
I have a dict of lists in python:
content = {88962: [80, 130], 87484: [64], 53662: [58,80]}
I want to turn it into a list of the unique values
[58,64,80,130]
I wrote a manual solution, but it’s a manual solution. I know there are more concise and more elegant way to do this with list comprehensions, map/reduce , itertools , etc. anyone have a clue ?
content = {88962: [80, 130], 87484: [64], 53662: [58,80]}
result = set({})
for k in content.keys() :
for i in content[k]:
result.add(i)
# and list/sort/print just to compare the output
r2 = list( result )
r2.sort()
print r2
use set()
and itertools.chain()
:
In [83]: content = {88962: [80, 130], 87484: [64], 53662: [58,80]}
In [84]: from itertools import chain
In [94]: x=set(chain(*content.values()))
In [95]: x
Out[95]: set([58, 64, 80, 130]) # a set, the items may or may not be sorted
In [96]: sorted(x) #convert set to a sorted list
Out[96]: [58, 64, 80, 130]
sorted(set(val
for row in content.itervalues()
for val in row))
set
gets us all the distinct values (like a dictionary, but without the overhead of storing values). sorted
then just takes the created set
and returns a list
sorted in ascending order.
list(reduce(lambda a, b: a.union(set(b)), content.itervalues(), set()))
The lambda
turns the two input arguments into sets and unions them.
The reduce
will do a left fold over the list that is passed to it — in this case, the lists that are the values of your dictionaries.
The reduce
will turn the result of this, which is a set
back into a list.
This can also be spelled:
list(reduce(lambda a, b: a | set(b), content.itervalues(), set()))
In python3.7 you can use a combination of .values
, and chain
.
from itertools import chain
sorted(set(chain(*content.values())))
# [58, 64, 80, 130]
# another option is `itertools.groupby`
from itertools import groupby
[k for k, g in groupby(sorted(chain(*content.values())))]
In python2.7
from itertools import chain
sorted(set(chain.from_iterable(content.itervalues())))
# [58, 64, 80, 130]
# another option is `itertools.groupby`
[k for k, g in groupby(sorted(chain.from_iterable(content.itervalues())))]
Double set comprehension:
Python 3:
sorted({x for v in content.values() for x in v})
Python 2:
sorted({x for v in content.itervalues() for x in v})
sorted(set(sum(content.values(), [])))
Use list comprehension to generate a non-unique list, convert it to a set to get the unique values, and then back into a sorted list. Perhaps not the most efficient, but yet another one line solution (this time with no imports).
Python 3:
sorted(list(set([val for vals in content.values() for val in vals])))
Python 2.7:
sorted(list(set([val for vals in content.itervalues() for val in vals])))