【问题标题】:Best way to find the intersection of multiple sets?找到多组交集的最佳方法?
【发布时间】:2011-02-02 06:15:43
【问题描述】:

我有一个集合列表:

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

我想要 s1 ∩ s2 ∩ s3 ...

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

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

【问题讨论】:

    标签: python set set-intersection


    【解决方案1】:

    我相信最简单的做法是:

    #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])
    

    【讨论】:

      【解决方案2】:

      Jean-François Fabre set.intesection(*list_of_sets) 答案绝对是最 Pyhtonic 并且正确地被接受的答案。

      对于那些想使用reduce的人,以下也可以:

      reduce(set.intersection, list_of_sets)

      【讨论】:

        【解决方案3】:

        从 Python 2.6 版开始,您可以对set.intersection() 使用多个参数,例如

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

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

        u = set.intersection(*setlist)
        

        *a_listlist expansion

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

        【讨论】:

        • 那么当参数可能为零时该怎么办?一行?
        • @RadioControlled 对于在 setlist 为空时工作的单线,请使用 u = set.intersection(*setlist) if setlist else set()
        • 对溶胶复杂性的任何评论。上面给出的?
        • @CKM,确切地说,我们是否需要事先按尺寸订购setlist 中的套装,或者该功能是否为我们这样做?这将与“应用第一个集合与列表其余部分的交集”的语句相矛盾。
        • @RadioControlled 没有集合的交集在数学上没有定义,所以这个应该失败。请参阅 Patrick Suppes 的“公理集合论”作为参考。
        【解决方案4】:

        显然set.intersection 是您想要的,但如果您需要“取所有这些的总和”、“取所有这些的乘积”、“取所有这些的异或”的概括,那么你要找的是reduce函数:

        from operator import and_
        from functools import reduce
        print(reduce(and_, [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
        

        print(reduce((lambda x,y: x&y), [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
        

        【讨论】:

        • 在这里,我很确定列表的顺序对速度很重要。按增加大小排序 - 或减少列表中相邻集合的预期交集大小,以更准确。
        【解决方案5】:

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

        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 可能不喜欢 reduce,但我有点喜欢它 :)

        【讨论】:

        • 您应该检查sets 的长度,而不是尝试访问sets[0] 并捕获IndexError
        • 这不是简单的检查; a_set 在最后返回时使用。
        • 你不能return reduce(sets[0], sets[1:]) if sets else set()吗?
        • 哈,是的,谢谢。代码应该改变,因为如果可以的话,应该避免依赖try/except。这是一种代码异味,效率低下,并且可以隐藏其他问题。
        【解决方案6】:

        从 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])
        

        【讨论】:

        • 不,它不能接受零迭代。
        【解决方案7】:

        如果您没有 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 程序员不喜欢它,including Guido himself

        大约 12 年前,Python 获得了 lambda、reduce()、filter() 和 map(),这归功于(我相信)一个错过了它们并提交了工作补丁的 Lisp 黑客。但是,尽管有 PR 值,我认为这些功能应该从 Python 3000 中删除。

        所以现在减少()。这实际上是我一直最讨厌的一个,因为除了一些涉及 + 或 * 的示例之外,几乎每次我看到带有非平凡函数参数的 reduce() 调用时,我都需要拿起笔和纸来在我理解 reduce() 应该做什么之前,先画出实际输入该函数的内容。所以在我看来,reduce() 的适用性几乎仅限于关联运算符,在所有其他情况下,最好明确地写出累加循环。

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-06
        相关资源
        最近更新 更多