Set.pop()不是't随机



从python文档中,"set.pop()从s中移除并返回任意元素"。在生成一些随机数据来测试程序时,我注意到这个pop()函数的奇怪行为。这是我的代码(python 2.7.3):

testCases = 10
numberRange = 500
poppedValues = []
greaterPercentages = []
for i in range (testCases):
s = Set()
""" inserting 100 random values in the set, in the range [0, numberRange) """
for j in range (100):
s.add(random.randrange(numberRange)) 
poppedValue = s.pop()
greaterCount = 0
""" counting how many numbers in the set are smaller then the popped value """
for number in s:
if poppedValue > number:
greaterCount += 1
poppedValues.append(poppedValue)
greaterPercentages.append(float(greaterCount) / len(s) * 100)
for poppedValue in poppedValues:
print poppedValue, 't',
print
for percentage in greaterPercentages:
print "{:2.2f}".format(percentage), 't',

我在这里做的是

  1. 在集合s中插入一些随机值,其中每个元素都在范围[0,numberRange)
  2. 从集合中弹出一个元素(根据文档,它应该是随机的)
  3. 计算集合中有多少元素小于弹出值

我预计弹出的值应该是随机的,并且集合中大约50%的数字将大于弹出的值。但似乎pop()几乎总是返回集合中的最低数字。以下是numberRange = 500的结果。第一行表示弹出元素的值。第二行是小于弹出值的元素的百分比。

9   0   3   1   409     0   1   2   4   0   
0 % 0 % 0 % 0 % 87 %    0 % 0 % 0 % 0 % 0 %

我用不同的numberRange值进行了这个测试。似乎对于集合元素的较低值,pop()几乎总是返回最低的元素。但对于更高的值,它返回一个随机元素。对于numberRange = 1000,结果为:

518     3586    3594    4103    2560    3087    4095    3079    3076    1622    
7 %     72 %    73 %    84 %    54 %    51 %    79 %    63 %    67 %    32 %

我认为这是非常随机的。为什么会有这种奇怪的行为?我做错什么了吗?

编辑:感谢大家的回答和评论,似乎"武断"并不能保证它会是"随机的"。

这是一个实现细节-set被实现为HashMap(类似于dict,但没有一个值槽),set.pop删除HashMap中的第一个条目,而int的哈希值是相同的int。

组合起来,这意味着按哈希值排序的set实际上也按条目模哈希表大小排序;在您的情况下,这应该接近自然排序,因为您只插入小范围的数字——如果您从randrange(10**10)而不是randrange(500)中提取随机数字,您应该会看到不同的行为。此外,根据您的插入顺序,由于哈希冲突,您可以从原始哈希顺序中获取一些值。

当医生说:

从s中移除并返回任意元素;如果为空,则引发KeyError

这意味着行为没有定义,实现可以做任何可能的事情。在这种情况下,实现的行为似乎是删除最小的值。仅此而已
事实上,set.pop()是基于HashMap的,并删除其中的第一个元素(较小的哈希代码)。在int的set的情况下,它是最小的int

在Python的其他实现中,可以返回一个随机值或第一个push。。。你不可能知道。

最新更新