如何检查任何给定集合中是否存在值

How to check if a value is present in any of given sets

说我有不同的集合(它们必须不同,我不能根据我正在使用的数据类型加入它们):

r = set([1,2,3])
s = set([4,5,6])
t = set([7,8,9])

检查给定变量是否存在于它们中的最佳方法是什么?

我正在使用:

if myvar in r \
   or myvar in s \
   or myvar in t:

但我想知道是否可以通过使用 set 的属性(例如 union.

以某种方式减少这种情况

以下有效,但我找不到定义多个联合的方法:

if myvar in r.union(s)
   or myvar in t:

我也想知道这个联合是否会以某种方式影响性能,因为我猜想会即时创建一个临时 set

您可以使用 reduce 函数来 将两个参数的函数累加到 iterable 的项目:

>>> r = set([1,2,3])
>>> s = set([4,5,6])
>>> t = set([7,8,9])
>>> 
>>> reduce(lambda x,y :x.union(y),[r,s,t])
set([1, 2, 3, 4, 5, 6, 7, 8, 9])

为了检查其中任何一个的成员资格,您可以在 any that is more efficient here because python use hash table for storing the sets and checking the member ship has O(1) in such data structures like dictionaries or frozenset.Also for check the membership in all of you sets use all.

中使用生成器表达式
if any(i in item for item in [r,s,t]):
    #do stuff

但在这种情况下(不适用于大型集合)使用 or 运算符更快。

value in r|s|t 

这是所有方面的基准:

~$ python -m timeit "r = set([1,2,3]);s = set([4,5,6]);t = set([7,8,9]);3 in reduce(lambda x,y :x.union(y),[r,s,t])"
1000000 loops, best of 3: 1.55 usec per loop
~$ python -m timeit "r = set([1,2,3]);s = set([4,5,6]);t = set([7,8,9]);3 in r|s|t"
1000000 loops, best of 3: 1.11 usec per loop
~$ python -m timeit "r = set([1,2,3]);s = set([4,5,6]);t = set([7,8,9]);any(3 in item for item in [r,s,t])"
1000000 loops, best of 3: 1.24 usec per loop
~$ python -m timeit "r = set([1,2,3]);s = set([4,5,6]);t = set([7,8,9]);3 in r.union(s).union(t)"
1000000 loops, best of 3: 1.19 usec per loop

注意 正如@Padraic Cunningham 提到的那样对于使用any 的大集合非常有效!

您可以使用内置 any:

r = set([1,2,3])
s = set([4,5,6])
t = set([7,8,9])
if any(myvar in x for x in [r,s,t]):
    print "I'm in one of them"

any 将在 returns True 的第一个条件下短路,因此您可以绕过构建一个潜在的巨大 union 或检查可能包含的大量集合.

而且我也想知道这个联合是否会以某种方式影响性能,因为我猜想会即时创建一个临时集。

根据 wiki.python.com s|tO(len(s)+len(t)) 而查找是 O(1) .

对于每个具有 l 个元素的 n 集合,迭代地执行 union 来构建集合将导致:

a.union(b).union(c).union(d) .... .union(n)

对于 a.union(b)O(2l+2l+l) a.union(b).union(c) 等同于 O(l+l) 等等,总计为 O(n*(n+1)/2)*l)

O(n^2*l) 是二次方的并且没有使用集合的性能优势。

any 的 n 个集合中的查找将在 O(n)

处执行

随便用:

if any(myvar in x for x in  (r,s,t))

set 查找是 0(1) 所以创建一个联合来检查变量是否在任何集合中是完全没有必要的,而不是简单地使用 inany 来检查,这将短路一旦找到匹配且不会创建新集。

而且我也想知道这个联盟是否会以某种方式影响性能

是的,合并集合当然会影响性能,它增加了复杂性,你每次都在创建一个新集合 O(len(r)+len(s)+len(t)) 所以你可以告别使用高效集合的真正意义查找。

所以最重要的是你想要保持高效的查找,你必须将集合联合一次并将它们保存在内存中创建一个新变量然后使用它来查找 myvar 所以初始创建将是 0(n),此后查找将是 0(1)

如果您不是每次都想首先创建联合进行查找,那么您将获得长度为 r+s+t -> set.union(*(r, s, t)) 的线性解决方案,而不是最坏的三个常量(平均)查找。这也意味着总是从 r,st.

的 added/removed 添加或删除任何元素。

在中等规模的集合上的一些实际时间恰恰显示了差异:

In [1]: r = set(range(10000))

In [2]: s = set(range(10001,20000))

In [3]: t = set(range(20001,30000))

In [4]: timeit any(29000 in st for st in (r,s,t))
1000000 loops, best of 3: 869 ns per loop  

In [5]: timeit 29000 in r | s | t
1000 loops, best of 3: 956 µs per loop

In [6]: timeit 29000 in reduce(lambda x,y :x.union(y),[r,s,t])
1000 loops, best of 3: 961 µs per loop

In [7]: timeit 29000 in r.union(s).union(t)
1000 loops, best of 3: 953 µs per loop

对联合进行计时显示几乎所有时间都花在了联合调用上:

In [8]: timeit r.union(s).union(t)
1000 loops, best of 3: 952 µs per loop

使用更大的集合并获取最后集合中的元素:

In [15]: r = set(range(1000000))

In [16]: s = set(range(1000001,2000000))

In [17]: t = set(range(2000001,3000000))


In [18]: timeit any(2999999 in st for st in (r,s,t))
1000000 loops, best of 3: 878 ns per loop

In [19]: timeit 2999999 in reduce(lambda x,y :x.union(y),[r,s,t])
1 loops, best of 3: 161 ms per loop

In [20]: timeit 2999999 in r | s | t
10 loops, best of 3: 157 ms per loop

无论使用 any 集有多大,实际上都没有区别,但是随着集大小的增长,使用并集的 运行 时间也会增长。

让它更快的唯一方法是坚持 or 但我们正在考虑几百纳秒的差异,这是创建生成器表达式和函数调用的成本:

In [22]: timeit 2999999 in r or 2999999 in s or 2999999 in t
10000000 loops, best of 3: 152 ns per loop

联合集 set.union(*(r, s, t)) 也是最快的,因为您不构建中间集:

In [47]: timeit 2999999 in set.union(*(r,s,t))
10 loops, best of 3: 108 ms per loop
In [49]: r | s | t  == set.union(*(r,s,t))
Out[49]: True

你可以简单地做

if myvar in r.union(s).union(t)

而且您不必担心此处的性能。是的,它会即时创建一个临时集,但因为它没有存储,所以会被垃圾收集。

| 是 python 中 sets 的联合运算符。您可以使用 | 定义多个集合的并集:

>>> r = set([1,2,3])
>>> s = set([4,5,6])
>>> t = set([7,8,9])
>>> r | s | t
set([1, 2, 3, 4, 5, 6, 7, 8, 9])