我有一个集合列表:

setlist = [s1,s2,s3...]

我想要s1∩s2∩s3…

我可以写一个函数,通过执行一系列成对的s1.intersection(s2),等等。

是否有推荐的、更好的或内置的方法?


当前回答

从2.6开始,set.intersection接受任意多个迭代对象。

>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s3 = set([2, 4, 6])
>>> s1 & s2 & s3
set([2])
>>> s1.intersection(s2, s3)
set([2])
>>> sets = [s1, s2, s3]
>>> set.intersection(*sets)
set([2])

其他回答

从2.6开始,set.intersection接受任意多个迭代对象。

>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s3 = set([2, 4, 6])
>>> s1 & s2 & s3
set([2])
>>> s1.intersection(s2, s3)
set([2])
>>> sets = [s1, s2, s3]
>>> set.intersection(*sets)
set([2])

从Python 2.6版起,你可以使用多个参数来set.intersection(),比如

u = set.intersection(s1, s2, s3)

如果集合在列表中,则转换为:

u = set.intersection(*setlist)

*a_list是列表展开

请注意,set.intersection不是一个静态方法,但它使用函数符号来应用第一个集合与列表其余部分的交集。如果参数列表为空,就会失败。

我认为最简单的做法是:

#assuming three sets
set1 = {1,2,3,4,5}
set2 = {2,3,8,9}
set3 = {2,10,11,12}

#intersection
set4 = set1 & set2 & set3

Set4将是set1, set2, set3的交集,并包含值2。

print(set4)

set([2])

如果你没有Python 2.6或更高版本,另一种方法是写一个显式的for循环:

def set_list_intersection(set_list):
  if not set_list:
    return set()
  result = set_list[0]
  for s in set_list[1:]:
    result &= s
  return result

set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print set_list_intersection(set_list)
# Output: set([1])

你也可以用reduce:

set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print reduce(lambda s1, s2: s1 & s2, set_list)
# Output: set([1])

然而,许多Python程序员不喜欢它,包括Guido自己:

About 12 years ago, Python aquired lambda, reduce(), filter() and map(), courtesy of (I believe) a Lisp hacker who missed them and submitted working patches. But, despite of the PR value, I think these features should be cut from Python 3000. So now reduce(). This is actually the one I've always hated most, because, apart from a few examples involving + or *, almost every time I see a reduce() call with a non-trivial function argument, I need to grab pen and paper to diagram what's actually being fed into that function before I understand what the reduce() is supposed to do. So in my mind, the applicability of reduce() is pretty much limited to associative operators, and in all other cases it's better to write out the accumulation loop explicitly.

这里我提供了一个多集交集的通用函数,试图利用可用的最佳方法:

def multiple_set_intersection(*sets):
    """Return multiple set intersection."""
    try:
        return set.intersection(*sets)
    except TypeError: # this is Python < 2.6 or no arguments
        pass

    try: a_set= sets[0]
    except IndexError: # no arguments
        return set() # return empty set

    return reduce(a_set.intersection, sets[1:])

Guido可能不喜欢减少,但我有点喜欢它:)