如果我们知道元素是唯一的,则可以快速扩展集合

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 和答案中弄清楚一些事情:

在进行迭代时,虽然我知道 setAmasterSet 不同,因为它是如何构造的(无需处理任何检查),但我需要一些迭代唯一性检查。

我想知道是否有办法“告诉”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.updateset.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> 并不难,这应该会快一个或多个数量级。

【讨论】:

以上是关于如果我们知道元素是唯一的,则可以快速扩展集合的主要内容,如果未能解决你的问题,请参考以下文章

如何生成多重集的所有排列?

如何判断两个集合的关系?

Java基础之集合框架(Collection接口和List接口)

架构师数据结构技术Day03-集合之Set

架构师数据结构技术Day03-集合之Set

Java 集合框架