40

I want to create a list (or set) of all unique values appearing in a list of lists in python. I have something like this:

aList=[['a','b'], ['a', 'b','c'], ['a']]

and i would like the following:

unique_values=['a','b','c']

I know that for a list of strings you can just use set(aList), but I can't figure how to solve this in a list of lists, since set(aList) gets me the error message

unhashable type: 'list'

How can i solve it?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
mihasa
  • 967
  • 2
  • 10
  • 20
  • You can flatten the list first. https://stackoverflow.com/search?q=[python]+flatten+list (fyi, in Python these are called lists, not arrays) – Felix Kling Jun 01 '15 at 04:47
  • Thanks, i didn't know which one was correct ;) – mihasa Jun 01 '15 at 04:53
  • I've seen list comprehensions doing that, but since my list is pretty big, i've guessed that in terms of efficiency that would be a bad call – mihasa Jun 01 '15 at 04:54
  • You can use a generator expression to avoid creating a second list: https://www.python.org/dev/peps/pep-0289/. But you have to iterate over all elements in the nested lists, there is no way around that. – Felix Kling Jun 01 '15 at 04:55
  • Related: [Union of multiple sets in python](https://stackoverflow.com/q/30773911/7851470) – Georgy Jan 06 '21 at 15:59

6 Answers6

65
array = [['a','b'], ['a', 'b','c'], ['a']]
result = {x for l in array for x in l}
cs95
  • 379,657
  • 97
  • 704
  • 746
dlask
  • 8,776
  • 1
  • 26
  • 30
  • that did the job, thank you very much! Isn't there a better way to do this kind of think without needing to iterate? (i'm a beginner but i thought that avoiding loops was the way to go when having a big len(array)) – mihasa Jun 01 '15 at 04:56
  • I am afraid there is no simpler way. You have a precisely defined input structure, you have a precisely defined output structure, and it's necessary to make the conversion. Since the conversion involves all elements it's necessary to "visit" all of them. Well, there are many different ways to obtain the result (see other posts) but the iteration is always present internally. – dlask Jun 01 '15 at 06:13
24

You can use itertools's chain to flatten your array and then call set on it:

from itertools import chain

array = [['a','b'], ['a', 'b','c'], ['a']]
print set(chain(*array))

If you are expecting a list object:

print list(set(chain(*array)))
jesterjunk
  • 2,342
  • 22
  • 18
Tanveer Alam
  • 5,185
  • 4
  • 22
  • 43
4
array = [['a','b'], ['a', 'b','c'], ['a']]
unique_values = list(reduce(lambda i, j: set(i) | set(j), array))
no coder
  • 2,290
  • 16
  • 18
4

You can use numpy.unique:

import numpy
import operator
print numpy.unique(reduce(operator.add, [['a','b'], ['a', 'b','c'], ['a']]))
# ['a' 'b' 'c']
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
3

The 2 top voted answers did not work for me, I'm not sure why (but I have integer lists). In the end I'm doing this:

unique_values = [list(x) for x in set(tuple(x) for x in aList)]
1

Try to this.

array = [['a','b'], ['a', 'b','c'], ['a']]
res=()
for item in array:
    res = list(set(res) | set(item))
print res

Output:

['a', 'c', 'b']
Haresh Shyara
  • 1,826
  • 10
  • 13