随便用一个:
if any(myvar in x for x in (r,s,t))
集合查找是0(1),因此完全没有必要创建一个联合来检查变量是否在任何集合中,而不是简单地使用in 和any 进行检查,一旦找到匹配项就会短路并且确实如此不创建新集合。
我也想知道这个联合是否会以某种方式影响性能
是的,合并集合当然会影响性能,它会增加复杂性,您每次都在创建一个新集合,即 O(len(r)+len(s)+len(t)),因此您可以告别使用高效查找集合的真正意义。
所以底线是您想要保持高效的查找,您必须将集合合并一次并将它们保存在内存中创建一个新变量,然后使用它来查找myvar,因此初始创建将是0(n) 之后查找将是 0(1)。
如果您不是每次都想先创建联合查找,您将获得长度为r+s+t -> set.union(*(r, s, t)) 的线性解决方案,而不是最坏的三个常量(平均)查找。这也意味着始终从 r,s 或 t 添加/删除的新联合集中添加或删除任何元素。
在中等大小的场景中,一些现实的时间安排正好显示了差异:
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