20

我知道 python 集合的元素没有排序。调用pop方法返回任意元素;我很好。

我想知道的是,当集合具有相同的历史时,pop 是否总是返回相同的元素。当然,在一个版本的 python 中,我不介意 python 的不同版本/实现是否做自己的事情。特别是,我问的是python 2.7。在这种情况下,这不仅仅是 api 的实现问题。

我在游戏的程序地牢生成器中使用了很多集合,我希望结果对于给定的种子是确定的。

4

5 回答 5

30

一般来说,答案是否定的。@Christophe 和 @Marcin (un) 有用地指出的 python 源代码显示元素按照它们在哈希表中出现的顺序弹出。因此,弹出顺序(可能是迭代顺序)确定性的,但仅适用于固定的哈希值。根据文档中的注释,数字就是这种情况,但字符串不是这种情况,顺便说一下,它也直接涉及您的问题:__hash__

请注意,默认情况下,str、bytes 和 datetime 对象的hash () 值是用不可预测的随机值“加盐”的。尽管它们在单个 Python 进程中保持不变,但它们在 Python 的重复调用之间是不可预测的。

[ ... ]

更改哈希值会影响 dicts、sets 和其他映射的迭代顺序。Python 从未对这种顺序做出保证(它通常在 32 位和 64 位版本之间变化)。

编辑:正如@Marcin 指出的那样,我引用的链接不适用于 Python 2。哈希随机化成为 Python 3.3 的默认设置。默认情况下,Python 2.7 没有有意的非确定性字符串散列。

通常,对于散列不是其值的可重复函数的任何对象(例如,如果散列基于内存地址),这都是一个问题。但相反,如果您为集合中的对象定义自己的__hash__方法,则可以预期它们将以可重现的顺序返回。(前提是该系列的历史和平台保持不变)。

于 2012-05-03T13:51:58.090 回答
6

在内部我认为情况类似于dict。顺序由哈希算法确定,在某些情况下会产生相同的结果。但是你不应该依赖它,因为一旦元素数量变大,集合就会遇到冲突(即它的内部散列),最终导致不同的排序。

简而言之:不,set.pop()不是确定性的。不要假设任何顺序,因为 API 明确指出,

集合对象是无序集合

于 2012-05-03T13:13:25.380 回答
4

该文档没有指定它必须是确定性的,因此您应该假设它不是。

于 2012-05-03T13:09:03.067 回答
2

如果你想强制确定性,你可以尝试类似

value = min(my_set)
my_set.remove(value)
于 2012-05-03T13:33:22.000 回答
-1

如果您确实针对某个特定版本的 python,那么您可以查看源代码并测试其行为(但测试良好 - 考虑负载因素等)。

如果您想要便携性,或者您发现set没有按要求执行,请使用有序字典(这里有一个:http ://code.activestate.com/recipes/576693/ ;还有很多其他的,所以找一个你喜欢的样子of),并将其改编为一组。

更新:这是一个有序集:http ://packages.python.org/Brownie/api/datastructures.html#brownie.datastructures.OrderedSet

于 2012-05-03T13:40:06.980 回答