【问题标题】:set and frozenset difference in implementationset和frozenset在实现上的区别
【发布时间】:2017-02-03 09:14:05
【问题描述】:

我在此链接上检查了 set 是可变的 https://docs.python.org/3/library/stdtypes.html#frozenset 而 freezeset 是不可变的,因此是可散列的。那么在python中set是如何实现的,元素查找时间是多少呢?实际上,我有一个元组列表 [(1,2),(3,4),(2,1)],其中元组中的每个条目都是一个 id,我想从这个列表中创建一个集合/冻结集。在这种情况下,集合应包含 (1,2,3,4) 作为元素。我可以使用frozenset从元组列表中一个一个地插入元素还是只能使用一个集合?

【问题讨论】:

  • 这纯粹是猜测,但我认为它们都以相同的方式实现,但frozenset 有一个写锁(因此是不变性)。在平均情况下,frozenset 上的查找时间应该更快,考虑到可变性(在sets 中),解释器可能需要更长的探测时间来查找/插入元素。但希望真正知道这一点的人会发布答案 - 我很感兴趣

标签: python


【解决方案1】:

您可以从生成器表达式或其他可迭代对象中实例化frozenset。在完成实例化之前,它不是不可变的。

>>> L = [(1,2),(3,4),(2,1)]
>>> from itertools import chain
>>> frozenset(chain.from_iterable(L))
frozenset([1, 2, 3, 4])

Python3.3 还进行了优化,当用作 in 运算符的右侧时,可将 {1, 2, 3, 4} 等集合文字转换为预先计算的冻结集。

【讨论】:

  • 你应该更喜欢 set 还是 freezeset,查找时间有什么区别?
  • @vkaul11,我不认为查找时间会有所不同
  • @vkaul11,frozenset 优化应该意味着集合是在编译时创建的,而不是每次执行代码时(在运行时)。根据具体情况,这种微优化可能会对性能产生显着影响。
【解决方案2】:

集和冻结集的实现方式与哈希表相同。 (否则他们为什么会要求他们的元素实现__hash__?)事实上,如果您查看Objects/setobject.c,他们几乎共享所有代码。这意味着只要哈希冲突没有失控,查找和删除是 O(1),插入是分期 O(1)。

创建frozenset 的常用方法是使用其他一些可迭代对象对其进行初始化。正如 gnibbler 所建议的,这里最合适的可能是itertools.chain.from_iterable

>>> L = [(1,2),(3,4),(2,1)]
>>> from itertools import chain
>>> frozenset(chain.from_iterable(L))
frozenset([1, 2, 3, 4])

【讨论】:

  • docs.python.org/2.4/lib/types-set.html 所以这里的链接已经过时了?目前有两种内置的集合类型,set 和frozenset。 set 类型是可变的——可以使用 add() 和 remove() 等方法更改内容。由于它是可变的,它没有哈希值,不能用作字典键或另一个集合的元素。 freezeset 类型是不可变的和可散列的——它的内容在创建后不能更改;但是,它可以用作字典键或另一个集合的元素
  • 虽然该链接是关于旧版本的,但其中的信息大部分仍然是正确的。不过,这与我所说的并不矛盾。大多数 freezeset 和 set 代码是完全相同的代码。它们甚至具有相同的迭代器类型。
  • 根据链接,set没有哈希值,那么它是如何用哈希表实现的?
  • 散列表不必是可散列的;它的键必须是可散列的。
【解决方案3】:

至于你的第一个问题,我实际上并没有检查源,但从集合需要包含可散列类型的对象,它是使用散列表实现的,并且它的查找这一事实似乎可以安全地假设因此,时间是 O(1)。

至于您的第二个问题,您不能将元素一个一个地插入到 frozenset 中(显然,因为它是不可变的),但是没有理由改用集合;只需从组成值的列表(或其他可迭代)中构造它,例如像这样:

data = [(1, 2), (3, 4), (2, 1)]
result = frozenset(reduce(list.__add__, [list(x) for x in data], []))

【讨论】:

  • list.__add__ 会给你二次性能。你应该在那里使用list.__iadd__
  • 当然,但这只是一个例子。为了演示,我尽量保持简单,尽管我不确定我最终取得了多大的成功。 :)
  • docs.python.org/2.4/lib/types-set.html 所以这里的链接已经过时了?目前有两种内置的集合类型,set 和frozenset。 set 类型是可变的——可以使用 add() 和 remove() 等方法更改内容。由于它是可变的,它没有哈希值,不能用作字典键或另一个集合的元素。 freezeset 类型是不可变的和可散列的——它的内容在创建后不能更改;但是,它可以用作字典键或另一个集合的元素。
  • 是什么让你觉得它已经过时了?这对我来说似乎是准确的。
  • 你在上面说过“我实际上并没有检查源,但是从集合需要包含可散列类型的对象这一事实来看,它似乎是安全的,它是使用散列表实现的,并且因此,它的查找时间是 O(1)。”并且链接说“它没有哈希值,不能用作字典键或另一个集合的元素。”
猜你喜欢
  • 1970-01-01
  • 2020-02-16
  • 2012-05-13
  • 1970-01-01
  • 2015-06-18
  • 2018-09-29
  • 1970-01-01
  • 2014-12-05
  • 1970-01-01
相关资源
最近更新 更多