121

I have a list of lists:

lists = [[1,4,3,2,4], [4,5]]

I want to flatten this list and remove all duplicates; or, in other words, apply a set union operation:

desired_result = [1, 2, 3, 4, 5]

What's the easiest way to do this?

Georgy
  • 12,464
  • 7
  • 65
  • 73
AJ.
  • 27,586
  • 18
  • 84
  • 94

7 Answers7

207

set.union does what you want:

>>> results_list = [[1,2,3], [1,2,4]]
>>> results_union = set().union(*results_list)
>>> print(results_union)
set([1, 2, 3, 4])

You can also do this with more than two lists.

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
sth
  • 222,467
  • 53
  • 283
  • 367
  • @sth, thanks for example, but when I run it I get an error: Traceback (most recent call last): File "so_example.py", line 33, in ? results_union=set().union(*result_lists) TypeError: union() takes exactly one argument (3 given) – AJ. Jan 28 '10 at 01:38
  • 1
    @AJ: According to the documentsion (http://docs.python.org/library/stdtypes.html#set.union) `union()` only supports multiple arguments for Python version 2.6 or higher. You seem to use a version before that, so you probably have to use an explicit loop: `total = set(); for x in results_list: total.update(x)` *(s/;/\n/)* – sth Jan 28 '10 at 02:15
  • 2
    You can also save creating an empty set by changing the 2nd line to `results_union = set.union(*(set(el) for el in results_list))` – Noel Evans Apr 13 '16 at 15:44
  • In this case it's less neat. But if the inputs on the first line were sets too... – Noel Evans Apr 13 '16 at 15:46
  • I'm just adding this as I found it useful to know how to union a bunch of sets at once – Noel Evans Apr 13 '16 at 15:55
  • @Jean-FrançoisFabre Wrong. – wim Mar 11 '19 at 18:23
  • 1
    @Jean-FrançoisFabre `TypeError: descriptor 'union' requires a 'set' object but received a 'list'` in python 3.6 atleast. – Paritosh Singh Mar 11 '19 at 18:31
  • 1
    If you use `set.union(*results_list)` you're binding the method descriptor manually, i.e. sending in the first element of `results_list` as "self". This makes some weird restrictions: 1. doesn't duck-type properly (now the first element must be a set or instance of a set subclass), and 2. union of an empty `results_list` will be an error (incorrect result - should return empty set). – wim Mar 11 '19 at 18:44
  • @Jean-FrançoisFabre Which version of python did you test it on successfully? I tried both 2.7 and 3.6 and got errors on both. – Code-Apprentice Mar 11 '19 at 18:55
  • sorry, actually I had a list of `set`s in input. Which explains why it worked for me, because first argument was used as `self`. Sorry for the confusion. – Jean-François Fabre Mar 11 '19 at 19:49
18

Since you seem to be using Python 2.5 (it would be nice to mention in your Q if you need an A for versions != 2.6, the current production one, by the way;-) and want a list rather than a set as the result, I recommend:

import itertools

...

return list(set(itertools.chain(*result_list)))

itertools is generally a great way to work with iterators (and so with many kinds of sequences or collections) and I heartily recommend you become familiar with it. itertools.chain, in particular, is documented here.

yatu
  • 86,083
  • 12
  • 84
  • 139
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • +1 A perfect example of a good time to dip into the wonderful `itertools` package. – gotgenes Jan 28 '10 at 03:48
  • 1
    @Alex thanks...edited my question to specify version and remove blame from myself for being so behind in versions :) I'll make it a point to look into itertools, appreciate the suggestion. – AJ. Jan 28 '10 at 03:48
  • @AJ, no blame, we all can suffer under such constraints after all (but please do remember to specify in future Qs!-); `itertools.chain` works fine in Python 2.4 as well, by the way. – Alex Martelli Jan 28 '10 at 03:55
3

You can also follow this style

In [12]: a = ['Orange and Banana', 'Orange Banana']
In [13]: b = ['Grapes', 'Orange Banana']
In [14]: c = ['Foobanana', 'Orange and Banana']

In [20]: list(set(a) | set(b) | set(c))
Out[20]: ['Orange and Banana', 'Foobanana', 'Orange Banana', 'Grapes']

In [21]: list(set(a) & set(b) | set(c))
Out[21]: ['Orange and Banana', 'Foobanana', 'Orange Banana']    
GrvTyagi
  • 4,231
  • 1
  • 33
  • 40
3

in comprehension way:

[*{ j for i in lists for j in i }]

or

[*functools.reduce(lambda x,y: {*x, *y}, lists)]
Randy
  • 151
  • 1
  • 2
2

Unions are not supported by lists, which are ordered, but are supported by sets. Check out set.union.

Justin R.
  • 23,435
  • 23
  • 108
  • 157
0

I used the following to do intersections, which avoids the need for sets.

a, b= [[1,2,3], [1,2]]
s = filter( lambda x: x in b, a)

or,

s = [ x for x in b if x in a ]
Bear
  • 1,117
  • 7
  • 11
  • 5
    Why would you even want to "avoid the need for sets"? They're faster, and clearer, for this purpose. And your "x in a" does a linear, brute-force search through the list each time you execute it. Yuck. – Peter Hansen Jan 28 '10 at 02:26
  • sets require type casting, and linear speed isn't bad unless you are dealing with a large N. – Bear Jan 28 '10 at 07:52
  • 3
    "Type casting"? In Python? Since when? Sets are basically dicts with only the keys, and they use hash and equality comparisons. Using "x in a" on a list does an equality comparison too. What's all this about type casting? – Peter Hansen Jan 28 '10 at 16:37
-2
desired_result = [x for y in lists for x in y]
Dharman
  • 30,962
  • 25
  • 85
  • 135