Set.pop()不是随机的吗?

Raf*_*mal 6 python random

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',
Run Code Online (Sandbox Code Playgroud)

我在这里做的是,

  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 %
Run Code Online (Sandbox Code Playgroud)

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

518     3586    3594    4103    2560    3087    4095    3079    3076    1622    
7 %     72 %    73 %    84 %    54 %    51 %    79 %    63 %    67 %    32 %
Run Code Online (Sandbox Code Playgroud)

我觉得这很随意.为何这种奇怪的行为?难道我做错了什么?

编辑:感谢大家的回答和评论,似乎"任意",它不能保证它是"随机的".

l4m*_*mpi 8

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

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

  • 你的第二段不正确.仅当插入的值相对于设置大小较小时才会出现这种情况.所有投注均以更大的价值结束. (2认同)

Max*_*ant 5

当医生说:

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

这意味着行为没有定义,实现可以做任何可能的事情.在这种情况下,似乎实现的行为是删除最小值.就这样.
实际上,set.pop()是基于a HashMap并删除了第一个元素(这是较小的哈希码).在set整数的情况下,它是最小的int.

在Python的其他实现可能会返回一个随机值或第一个推...你不能知道.