2014-01-09 35 views
2

python docs,「set.pop()移除並返回s中的任意元素」。在生成一些隨機數據來測試程序時,我注意到了這個pop()函數的奇怪行爲。這裏是我的代碼(蟒蛇2.7.3):Set.pop()不是隨機的嗎?

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 % 

我認爲這是非常隨機的。爲什麼這個奇怪的行爲難道我做錯了什麼?

編輯:感謝大家的回答和評論,似乎通過「任意」,它不能保證它是「隨機的」。

+4

這不是隨機的,它是無序的。 – Matthias

+4

「隨意」的文檔並不意味着「隨機」,它們的意思是「不依賴於任何特定的值,實施細節可能會在沒有警告的情況下發生變化」 – wim

+0

隨機並不意味着它的分佈非常好,甚至不可預知。這意味着你將來不能依賴任何觀察。 – Alfe

回答

7

這是一個實現細節 - set作爲一個HashMap(類似於dict但沒有一個值的狹槽)來實現,set.pop去除在HashMap中的第一個條目,以及一個小號int散列值是相同的INT。

這意味着您的set(按散列值排序)實際上是由條目以及模塊散列表大小排序的;這應該接近自然排序在你的情況下,因爲你只是從小範圍插入數字 - 如果你從randrange(10**10)而不是randrange(500)隨機數字,你應該看到不同的行爲。此外,根據您的插入順序,由於散列衝突,您可以從原始散列順序中獲取一些值。

+2

您的第二段不正確。只有當插入的值相對於設置的大小較小時纔是如此。所有投注均以較大的價格出局。 – interjay

+0

@interjay是的,你是對的,編輯ATM - 它當然是通過哈希表大小的模數來排序;但是由於OP在小範圍內插入數字,所以對他的情況應該大部分是正確的。 – l4mpi

5

當醫生說:

撈出從s返回任意的元件;如果爲空,則會引發KeyError

這意味着行爲未定義,並且實現可以執行任何可能的操作。在這種情況下,似乎執行的行爲是刪除最小值。就這樣。
實際上,set.pop()基於HashMap並刪除了第一個元素(這是較小的哈希碼)。在整數set的情況下,它是最小的int

關於Python的其他實現可能會返回一個隨機值或第一次推送...您無法知道。

+0

這是一個實現細節,由'set'作爲HashMap的實現引起的,並且整數的散列值爲 – l4mpi