如果我们知道元素是唯一的,则可以快速扩展集合
Posted
技术标签:
【中文标题】如果我们知道元素是唯一的,则可以快速扩展集合【英文标题】:Quick way to extend a set if we know elements are unique 【发布时间】:2013-06-01 02:55:58 【问题描述】:我正在执行该类型的多次迭代:
masterSet=masterSet.union(setA)
随着集合的增长,执行这些操作所花费的时间也在增长(正如人们所期望的那样,我猜)。
我希望花费时间检查 setA 的每个元素是否已经在 masterSet 中?
我的问题是,如果我知道 masterSet 不包含 setA 中的任何元素,我可以更快地做到这一点吗?
[更新]
鉴于这个问题仍然在吸引观点,我想我会从下面的 cmets 和答案中弄清楚一些事情:
在进行迭代时,虽然我知道 setA
与masterSet
不同,因为它是如何构造的(无需处理任何检查),但我需要一些迭代唯一性检查。
我想知道是否有办法“告诉”masterSet.union()
程序这次不要打扰唯一性检查,因为我知道这与 masterSet
不同,只需快速添加这些元素,相信程序员的断言他们肯定是不同的。 Perhpas 通过调用一些不同的“.unionWithDistinctSet()
”程序什么的。
我认为响应表明这是不可能的(无论如何,真正设置的操作应该足够快),但使用 masterSet.update(setA)
而不是 union 会稍微快一些。
我已经接受了最明确的答复,解决了我当时遇到的问题并继续我的生活,但我仍然很想知道我假设的 .unionWithDistinctSet()
是否会存在?
【问题讨论】:
你怎么知道元素不在masterSet
中?您是否先测试了元素?
否 - 在某些迭代中,我知道通过 setA 的生成方式,masterSet 中不能有任何元素
只是检查;可能有机会直接更新masterSet
,而不必稍后再更新。
【参考方案1】:
您可以使用set.update
更新您的主集。这样可以节省一直分配新集合的时间,因此它应该比set.union
快一点...
>>> s = set(range(3))
>>> s.update(range(4))
>>> s
set([0, 1, 2, 3])
当然,如果你在循环中这样做:
masterSet = set()
for setA in iterable:
masterSet = masterSet.union(setA)
您可能会通过执行以下操作来提升性能:
masterSet = set().union(*iterable)
最终,集合的成员资格测试是 O(1)(在平均情况下),因此测试元素是否已包含在集合中并不会真正影响性能。
【讨论】:
@jamylak -- 出于某种原因,更新集比dict.update
或set.union
少得多。 (我必须dir(set)
才能确定不是set.extend
;-)
我打算建议|=
@jamylak - 我猜他们最终会是相同的方法......虽然可能不是。使用|=
,右侧可能需要是一个集合,而使用set.extend
放宽该限制。
哦,对了,我记得我也得出了这个结论,因此没有发布【参考方案2】:
正如 mgilson 指出的那样,您可以使用 update
从另一个集合就地更新一个集合。这实际上会稍微快一点:
def union():
i = set(range(10000))
j = set(range(5000, 15000))
return i.union(j)
def update():
i = set(range(10000))
j = set(range(5000, 15000))
i.update(j)
return i
timeit.Timer(union).timeit(10000) # 10.351907968521118
timeit.Timer(update).timeit(10000) # 8.83384895324707
【讨论】:
【参考方案3】:如果您知道自己的元素是独一无二的,那么集合不一定是最好的结构。
简单的列表可以更快地扩展。
masterList = list(masterSet)
masterList.extend(setA)
【讨论】:
在某些迭代中,我需要测试唯一性,但在大多数情况下,我知道 setA 和 masterSet 是不同的。有没有办法“告诉” union() 方法(或使用替代方法)我知道集合是不同的? @mgilson 你假设 OP 没有进行任何成员资格检查?? @jamylak -- 是的。我觉得这回答了问题的最后一句话。 另一方面,一个集合中的检查是o(1),所以联合中的开销不是很大。【参考方案4】:当然,当__eq__(..)
方法非常昂贵时,放弃此检查可能会节省大量资金。在 CPython 实现中,调用 __eq__(..)
时,集合中已经存在散列到相同数字的每个元素。 (参考:source code for set
。)
然而,一百万年后永远不会有这个功能,因为它开辟了另一种破坏集合完整性的方法。与此相关的麻烦远远超过(通常可以忽略不计的)性能增益。如果这被确定为性能瓶颈,那么编写 C++ 扩展并使用其 STL <set>
并不难,这应该会快一个或多个数量级。
【讨论】:
以上是关于如果我们知道元素是唯一的,则可以快速扩展集合的主要内容,如果未能解决你的问题,请参考以下文章