94

I am playing with python and am able to get the intersection of two lists:

result = set(a).intersection(b)

Now if d is a list containing a and b and a third element c, is there an built-in function for finding the intersection of all the three lists inside d? So for instance,

d = [[1,2,3,4], [2,3,4], [3,4,5,6,7]]

then the result should be

[3,4]
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
Legend
  • 113,822
  • 119
  • 272
  • 400

6 Answers6

122
set.intersection(*map(set,d))
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • 1
    Not sure what's wrong here. Now it gives me: `TypeError: intersection() takes exactly one argument (2 given)` – Legend Oct 04 '10 at 04:20
  • 1
    Thanks a lot. +1 for that. I just couldn't use it because of my Python version :( – Legend Oct 04 '10 at 04:47
  • 2
    If the `d` variable may have a length of zero the `set.intersection` function will raise a `TypeError` exception. I would recommend catching that exception and return `set()` (an empty set) instead in that degenerate case. This is better than checking the `len` of `d` beforehand as it may be a generator. – Aaron Robson Sep 26 '12 at 23:51
  • @AaronR: Good point, but the degenerate solution for set intersection is the universal set, not the empty set. since there's no compact way to represent that in python, raising an exception (probably catching the type error and raising something more sensible) is still probably the right way to handle it. Returning an empty set *is* the right thing to do for set union, however. – SingleNegationElimination Sep 27 '12 at 05:36
  • @TokenMacGuy: Yes, you're quite right; by analogy with http://en.wikipedia.org/wiki/Empty_product it would be the only set which would be guaranteed to not change the result of an intersection. – Aaron Robson Sep 28 '12 at 19:59
  • This is briliant but a further explanation would be appreciated and useful. – ciurlaro Nov 09 '20 at 17:07
  • @CesareIurlaro It's a built-in function... Documentation link => [Built-in Types — Python 3.9.6 documentation](https://docs.python.org/3/library/stdtypes.html#frozenset.intersection) – user202729 Aug 15 '21 at 03:45
65

for 2.4, you can just define an intersection function.

def intersect(*d):
    sets = iter(map(set, d))
    result = sets.next()
    for s in sets:
        result = result.intersection(s)
    return result

for newer versions of python:

the intersection method takes an arbitrary amount of arguments

result = set(d[0]).intersection(*d[1:])

alternatively, you can intersect the first set with itself to avoid slicing the list and making a copy:

result = set(d[0]).intersection(*d)

I'm not really sure which would be more efficient and have a feeling that it would depend on the size of the d[0] and the size of the list unless python has an inbuilt check for it like

if s1 is s2:
    return s1

in the intersection method.

>>> d = [[1,2,3,4], [2,3,4], [3,4,5,6,7]]
>>> set(d[0]).intersection(*d)
set([3, 4])
>>> set(d[0]).intersection(*d[1:])
set([3, 4])
>>> 
Emin Bugra Saral
  • 3,756
  • 1
  • 18
  • 25
aaronasterling
  • 68,820
  • 20
  • 127
  • 125
  • @AaronMcSmooth: It gives me `AttributeError: 'list' object has no attribute 'intersection'` if I do that. Am I missing something? – Legend Oct 04 '10 at 04:19
  • @Legend. you have to map it to a set first. I somehow missed the fact that they were lists. After that, you can just pass lists (or any other iterable) to the `intersection` method – aaronasterling Oct 04 '10 at 04:20
  • @AaronMcSmooth: Actually, not sure why but I'm getting this error no matter what solution I try: `TypeError: intersection() takes exactly one argument (3 given)` – Legend Oct 04 '10 at 04:24
  • @Legend. both my answer and TokenMacGuy's work for me on python 2.6 and 3.1 – aaronasterling Oct 04 '10 at 04:26
  • @AaronMcSmooth: Aah... Is there some solution for Python 2.4 by any chance? – Legend Oct 04 '10 at 04:27
  • @AaronMcSmooth: Today's a bad day. Sorry. When I define the intersection, it gives me: `UnboundLocalError: local variable 'set' referenced before assignment` I don't understand why it is considering set as a local variable. – Legend Oct 04 '10 at 04:38
  • @AaronMcSmooth: I edited your answer to something that works. Thanks for the help. – Legend Oct 04 '10 at 04:46
  • 16
    @Legend. Thanks for cleaning up my post. but remember: 'Thus spoke the Lord: "Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are the devil's apples!"' – aaronasterling Oct 04 '10 at 04:51
  • @AaronMcSmooth: Aye aye captain! Thou shall remember that for next time... Thanks! :) – Legend Oct 04 '10 at 05:12
  • Lobbeth thou thy holy space bar of Antioch. – intuited Oct 04 '10 at 08:41
  • I believe you made a typo: `result = set(d[0]).intersection(*d[:1])` should be: `result = set(d[0]).intersection(*d[1:])`. Otherwise you're just getting the first list back. – Alex Feb 05 '21 at 03:21
13

@user3917838

Nice and simple but needs some casting to make it work and give a list as a result. It should look like:

list(reduce(set.intersection, [set(item) for item in d ]))

where:

d = [[1,2,3,4], [2,3,4], [3,4,5,6,7]]

And result is:

[3, 4]

At least in Python 3.4

Bartek
  • 131
  • 1
  • 4
13

You can get the intersection of an arbitrary number sets using set.intersection(set1, set2, set3...). So you just need to convert your lists into sets and then pass them to this method as follows:

d = [[1,2,3,4], [2,3,4], [3,4,5,6,7]]  
set.intersection(*[set(x) for x in d])  

result:

{3, 4}
David Buck
  • 3,752
  • 35
  • 31
  • 35
4

Lambda reduce.

from functools import reduce #you won't need this in Python 2
l=[[1, 2, 3, 4], [2, 3, 4], [3, 4, 5, 6, 7]]
reduce(set.intersection, [set(l_) for l_ in l])
  • 3
    you require a list of set , this would fail saying that 'descriptor intersection requires set' – tj89 Sep 20 '17 at 06:08
4

I find reduce() to be particularly useful. In fact, the numpy documents recommend using reduce() to intersect multiple lists: numpy.intersect1d reference

To answer your question:

import numpy as np
from functools import reduce
# apply intersect1d to (a list of) multiple lists:
reduce(np.intersect1d, [list_1, list_2, ... list_n])
mirekphd
  • 4,799
  • 3
  • 38
  • 59
sgyzetrov
  • 191
  • 1
  • 9