配列のシャッフルの決まり文句は「sort_by{ rand }」だった
配列要素のランダム抽出でRuby1.8.7をチェック - 技術メモ的なモノと気になるモノ
元のget_random_dataはエラーが出てたので修正。Ruby 1.8.6以前ではあれこれ考えるよりも「sort_by { rand }」するのが手っ取り早い。
だが、Ruby 1.8.7になるとそんなイディオム知らなくても「shuffle」と言えばいいだけ。意図がわかって文字数減って楽チン。
def get_random_data(data,max_size=nil) max_size = data.size unless max_size data_list = data.dup #sliceを使うのでコピー (1..max_size).map {|i|data_list.slice!(rand(data_list.size))} end def shuffle_n(data,n=nil) a = data.sort_by { rand } n ? a[0,n] : a end a = [1,2,3,4,5] get_random_data a # => [3, 5, 4, 2, 1] get_random_data a,2 # => [3, 1] shuffle_n a # => [3, 4, 1, 2, 5] shuffle_n a,2 # => [5, 2]
Ruby 1.8.7への差分は俺の挙げたリストだけでほとんど揃っているだろう。あとはバグ修正とか。
追記
すみっこ
ランダムソート(笑)とは - 西尾泰和のはてなダイアリー
ランダムソートの落とし穴については初知り。納得。
たしかに「比較関数に乱数を設定した」場合はばらつきが出る。
h = Hash.new(0) 7000.times do h[(0..6).sort {rand(3)-1 }.first] += 1 end h.sort # => [[0, 1983], [1, 587], [2, 621], [3, 494], [4, 1082], [5, 655], [6, 1578]]
しかし、sort_byはシュウォーツ変換によるものだ。乱数をN回発生させて、発生させた乱数を基準にsortする。だからほぼ均等になる。
h = Hash.new(0) 7000.times do h[(0..6).sort_by { rand }.first] += 1 end h.sort # => [[0, 997], [1, 1010], [2, 976], [3, 975], [4, 999], [5, 994], [6, 1049]]