从python docs,“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',
我在这里做的是,
s
中插入一些随机值,其中每个元素的范围为[0,numberRange
)我预计弹出的值应该是随机值,并且集合中大约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 %
我觉得很随意。为何这种奇怪的行为?我做错了吗?
编辑:感谢大家的回答和评论,似乎“任意”,并不能保证它会“随机”。
答案 0 :(得分:8)
它是一个实现细节 - set
实现为HashMap(类似于dict
但没有值的插槽),set.pop
删除了第一个条目HashMap和int
的哈希值是相同的int。
组合,这意味着您按哈希值排序的set
实际上也是按条目模数哈希表大小排序的;这应该接近您的情况下的自然顺序,因为您只插入小范围内的数字 - 如果您从randrange(10**10)
而不是randrange(500)
获取随机数,您应该会看到不同的行为。此外,根据您的广告订单顺序,您可以通过哈希冲突从原始哈希顺序中获取一些值。
答案 1 :(得分:5)
当医生说:
从s中删除并返回任意元素;如果为空,则引发KeyError
这意味着行为没有定义,实现可以做任何事情。在这种情况下,似乎实现的行为是删除最小值。就是这样
实际上,set.pop()
基于HashMap
并删除了它的第一个元素(这是较小的哈希码)。对于set
的整数,它是最小的int
。
在Python的其他实现上可以返回一个随机值或者第一次推送......你无法知道。