2

I am using Python 2.5.4. From here: Python -Intersection of multiple lists?

I have this:

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

The following works as expected:

intersect([1,2,3,4], [2,3,4], [3,4,5,6,7])

But, I have something that looks more like the following:

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

If I call it like:

intersect(d)

I get:

TypeError: list objects are unhashable

How do I transform the d above into something intersect() can take?

Community
  • 1
  • 1
Doo Dah
  • 3,979
  • 13
  • 55
  • 74
  • 1
    I don't want to sound patronizing, but simply copying and pasting code does not get you very far. You got an error which you did not understand probably because you don't know how the code actually works. When you take code from somewhere else, make sure you understand how/why it works. It's a good way to learn new aspects of a language! – Felix Kling Nov 16 '12 at 21:32

3 Answers3

10

You need to pass the contents of your list as separate parameters:

intersect(*d)

What happens otherwise is that the whole list is being used as one set instead. The *d syntax indicates to Python that you want to use d as a sequence of parameters to the function, instead using the whole d list as just one parameter.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • @ScottV: Note that `*d` in function definitions like above has basically the oposite (but related) meaning: All arguments passed to `intersect` can be accessed via the sequence `d`. That way you can create variadic functions. – Felix Kling Nov 16 '12 at 21:36
1

Martijn's answer is correct. I just want to add that this can be done in a much more simple and presumably efficient manner:

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

example:

>>> d = [ [1,2,3,4], [2,3,4], [3,4,5,6,7] ]
>>> set(d[0]).intersection(*d[1:])
set([3, 4])

disclaimer -- this was tested on python 2.7. I don't know about 2.5

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • If you have python2.5 handy, and can verify that this still works on that version, post a comment so I can remove the disclaimer at the bottom :). Thanks! – mgilson Nov 16 '12 at 21:48
  • With Python 2.5, if I try to run your example, I get "TypeError: intersection() takes exactly one argument (2 given)". – Doo Dah Nov 19 '12 at 15:48
  • @ScottV -- Thanks for checking this. It's a bummer that feature wasn't added in 2.5 :( -- I suppose I'll leave this answer only for posterity as I truly believe this is the way to solve your problem with newer versions of python. – mgilson Nov 19 '12 at 15:51
1

Here's another way to implement it:

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

reduce((lambda x, y: x & y), map(set, d))

or

reduce(operator.and_, map(set, d))

This is also valid in 2.5 and previous versions.

Eric
  • 95,302
  • 53
  • 242
  • 374