15

如果我有可变数量的集合(我们称之为数字n),每个集合最多有m个元素,那么计算所有集合对的成对交集的最有效方法是什么?请注意,这与所有n 个集合的交集不同。

例如,如果我有以下集合:

A={"a","b","c"}
B={"c","d","e"}
C={"a","c","e"}

我希望能够找到:

intersect_AB={"c"}
intersect_BC={"c", "e"}
intersect_AC={"a", "c"}

另一种可接受的格式(如果它使事情变得更容易的话)是给定集合中的项目到包含相同项目的集合的映射。例如:

intersections_C={"a": {"A", "C"},
                 "c": {"A", "B", "C"}
                 "e": {"B", "C"}}

我知道这样做的一种方法是创建一个字典,将所有n 个集合的并集中的每个值映射到它出现的集合列表,然后遍历所有这些值以创建intersections_C如上所述的列表,但是我不确定随着n的增加和集合的大小变得太大,它是如何扩展的。

一些额外的背景信息:

  1. 每个集合的长度大致相同,但也非常大(足够大,以至于将它们全部存储在内存中是一个现实的问题,并且避免这种情况的算法将是首选但不是必需的)
  2. 与集合本身的大小相比,任何两个集合之间的交集的大小都非常小
  3. 如果它有帮助,我们可以假设我们需要对输入集的排序做任何事情。
4

3 回答 3

8

这应该做你想做的

import random as RND
import string
import itertools as IT

模拟一些数据

fnx = lambda: set(RND.sample(string.ascii_uppercase, 7))
S = [fnx() for c in range(5)]

生成 S 中集合的索引列表,以便可以在下面更简洁地引用这些集合

idx = range(len(S))

获取 S 中所有可能的唯一项对;然而,由于集合交集是可交换的,我们想要组合而不是排列

pairs = IT.combinations(idx, 2)

编写一个函数执行设置的交集

nt = lambda a, b: S[a].intersection(S[b])

将此函数折叠在对上并将每个函数调用的结果键入其参数

res = dict([ (t, nt(*t)) for t in pairs ])

下面的结果,根据 OP 中引用的第一个选项格式化,是一个字典,其中的是两个序列的集合交集;键控到由这些序列的两个索引组成的元组的每个值

这个解决方案实际上只是行代码:(i)计算排列;(ii) 然后对每个排列应用一些函数,将返回值存储在结构化容器(键值)容器中

此解决方案的内存占用很小,但您可以通过在最后一步返回生成器表达式来做得更好,即

res = ( (t, nt(*t)) for t in pairs )

请注意,使用这种方法,对的序列和相应的交集都没有写入内存——即,res都是迭代器。

于 2014-12-09T01:10:48.687 回答
3

如果我们可以假设输入集是有序的,那么伪合并排序方法似乎很有前途。将每个集合视为已排序的流,并行推进流,始终只推进所有当前迭代器中值最低的流。每次推进迭代器时将每个当前值与新的最小值进行比较,并将匹配项转储到您的相同项目集合中。

于 2014-12-09T01:27:12.483 回答
-4

如何使用集合的交集方法。见下文:

A={"a","b","c"}
B={"c","d","e"}
C={"a","c","e"}

intersect_AB = A.intersection(B)
intersect_BC = B.intersection(C)
intersect_AC = A.intersection(C)

print intersect_AB, intersect_BC, intersect_AC
于 2014-12-09T05:11:26.000 回答