36

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
Jonathan Vanasco
  • 15,111
  • 10
  • 48
  • 72

7 Answers7

59

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})
nneonneo
  • 171,345
  • 36
  • 312
  • 383
17

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())))]
Elmer
  • 809
  • 9
  • 15
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
7

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]
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • Cool - just a couple of bits though - the `list` is redundant in `sorted(list(x))` and `*content.values()` is spelt `chain.from_iterable`... – Jon Clements Oct 22 '12 at 17:05
  • I prefer `chain()` as it takes less amount of characters, thanks for the `sorted(list(x))` part. :) – Ashwini Chaudhary Oct 22 '12 at 17:09
  • Isn't chain.from_iterable more efficient though? Using just chain means you are unpacking the sequence. Whereas from_iterable does it in the generator. – jdi Oct 22 '12 at 17:13
4
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.

Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
  • 1
    Note that this won't work in python3. Also, I think this answer explains the list comprehension a little better than the accepted answer. I like how you formatted it. – Tom Myddeltyn Dec 01 '16 at 13:58
4
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()))
Sam Mussmann
  • 5,883
  • 2
  • 29
  • 43
3
sorted(set(sum(content.values(), [])))
georg
  • 211,518
  • 52
  • 313
  • 390
2

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])))
mikeviescas
  • 507
  • 4
  • 7