43

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 
2
  • 8
    Within 3 minutes there are 4 great answers, which all prove i need to read more of the standard library docs. Commented Oct 22, 2012 at 17:03
  • 4
    Chuckles That feeling doesn't really ever go away - there are a lot of batteries included in the standard lib. Commented Oct 22, 2012 at 17:06

7 Answers 7

66

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}) 
Sign up to request clarification or add additional context in comments.

5 Comments

A link to the set comprehension documentation would make this perfect.
this is really concise and nice to look at. You get the best answer out of sea of really excellent answers.
Note: This won't work in Python3, itervalues has been removed.
@TomMyddeltyn substitute itervalues for values in python 3 (just like you'd substitute iteritems for items with dictionaries) since Python 3 favors lazy iteration
The answer by @Jon Clements is better at leveraging ptyhon standard libs.
19

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

1 Comment

Worth pointing out: *content.values() will immediately expand the entire iterable into an argument tuple. Use chain.from_iterable(content.values()) to preserve the laziness of values() in Python 3.
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] 

3 Comments

Cool - just a couple of bits though - the list is redundant in sorted(list(x)) and *content.values() is spelt chain.from_iterable...
I prefer chain() as it takes less amount of characters, thanks for the sorted(list(x)) part. :)
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.
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.

1 Comment

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

3 Comments

This will create a bunch of temporary sets as it loops.
Thanks! I was editing to add some explanation and realized and (I think) fixed that.
To my eye, a.union(set(b) is more explicit and more readable. a | set (b) certainly works as well.
3
sorted(set(sum(content.values(), []))) 

Comments

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

1 Comment

This should be the most elegant solution leveraging list/dictionary comprehension.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.