假设我有不同的设置(它们必须不同,我不能按照我正在处理的数据加入它们):
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
将会动态创建。
答案 0 :(得分:16)
您可以使用内置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
会在返回True
的第一个条件上发生短路,因此您可以绕过构建潜在巨大的union
或检查可能包含的大量集合。
而且我也想知道这个联盟是否会影响某种程度的表现,因为我想一个临时的设置将会动态创建。
根据wiki.python.com s|t
O(len(s)+len(t))
,而查询为O(1)
。
对于每个n
元素的l
集合,迭代执行union
以构建集合将导致:
a.union(b).union(c).union(d) .... .union(n)
相当于O(l+l)
和a.union(b)
O(2l+2l+l)
的{{1}}等等,总计为a.union(b).union(c)
。
O(n*(n+1)/2)*l)
是二次的,并且无法使用集合的性能优势。
使用O(n^2*l)
的n个集合中的查找将在any
答案 1 :(得分:14)
只需使用任何:
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
有多大都没有区别,但随着集合大小的增加,使用union的运行时间也会增长。
使其更快的唯一方法是坚持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
答案 2 :(得分:5)
|
是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])
答案 3 :(得分:4)
您可以使用reduce
函数将两个参数的函数累加应用于可迭代项:
>>> 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
中使用更高效的生成器表达式,因为python使用hash table来存储集合并检查成员船具有O(1 )在诸如词典或frozenset
之类的数据结构中。另外,为了检查,你们所有人的成员资格都使用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
的大型集合非常有效!
答案 4 :(得分:2)
你可以简单地做
if myvar in r.union(s).union(t)
你不必担心这里的表现。是的,它会动态创建一个临时集,但因为它没有被存储,所以会收集垃圾。