2012-07-01 103 views
2

我知道我可以用樣本方法從數組中挑選一個隨機元素,但這會使元素被選中不止一次。我可以先排序數組,然後從第一個到最後一個元素,但我知道這是內存密集型的,如果可能的話,我正在尋找一個不太密集的方法!從Ruby中的數組中挑選隨機元素ONCE我只知道

+0

爲什麼說洗牌數組是內存密集型的?大多數天真的實現將數組混合就位。 – aromero

+0

Docs聲明'#sample'不會多次選擇元素。 '[1,2] .sample(3)'返回'[1,2]'或者[2,1]'。 – Nick

回答

8

洗牌數組不佔用大量內存。 Ruby有一個默認的shuffle實現,它被稱爲Array.shuffle!。看着這個,你可以看到源代碼(它的C):

rb_ary_shuffle_bang(ary) 
    VALUE ary; 
{ 
    long i = RARRAY(ary)->len; 

    rb_ary_modify(ary); 
    while (i) { 
     long j = rb_genrand_real()*i; 
     VALUE tmp = RARRAY(ary)->ptr[--i]; 
     RARRAY(ary)->ptr[i] = RARRAY(ary)->ptr[j]; 
     RARRAY(ary)->ptr[j] = tmp; 
    } 
    return ary; 
} 

此實現沿用經典Fisher-Yates algorithm

所以:

  1. 洗牌使用shuffle!到位陣列。時間複雜度爲O(n),不需要額外的內存。
  2. 遍歷數組。時間複雜度爲O(n),不需要額外的內存(只有一個整數才能保存當前索引)。

總的來說,你有你所需要的沒有額外的內存和時間複雜度O(n)

0

你必須跟蹤你已經選擇的元素;你打算怎麼做,把他們放在他們自己的陣列中?

隨機和重複。與追蹤已選擇的元素相比,這不會佔用更多內存。

1

如果數組元素是真的非常大,您可以嘗試簡單地洗牌索引列表,並遍歷是:

a = %w{a b c d e f g h} 

[*0...a.size].shuffle.each do |index| 
    puts a[index] 
end 
10

sample需要一個參數:

[*(1..10)].sample(5) #=>[3, 4, 1, 8, 9] 

否元件將被選擇兩次。

+0

不是我的問題,但這是我不知道的事情,並且可以預見在將來有用。 +1 – KChaloux

相關問題