これは私がこれまでに持っているものです:
myArray.map!{ Rand(max) }
ただし、リスト内の番号が一意でない場合もあります。リストに一意の番号のみが含まれていることを確認するにはどうすればよいですか。大きいリストを作成し、そこからn個の一意の番号を選択する必要はありません。
編集:
これがループなしで実行されることを本当に望んでいます-可能であれば。
これはセットを使用します:
require 'set'
def Rand_n(n, max)
randoms = Set.new
loop do
randoms << Rand(max)
return randoms.to_a if randoms.size >= n
end
end
(0..50).to_a.sort{ Rand() - 0.5 }[0..x]
(0..50).to_a
は任意の配列に置き換えることができます。 0は「最小値」、50は「最大値」、xは「必要な値の数」
もちろん、xがmax-minより大きいことを許可することは不可能です:)
これがどのように機能するかを拡大して
(0..5).to_a ==> [0,1,2,3,4,5]
[0,1,2,3,4,5].sort{ -1 } ==> [0, 1, 2, 4, 3, 5] # constant
[0,1,2,3,4,5].sort{ 1 } ==> [5, 3, 0, 4, 2, 1] # constant
[0,1,2,3,4,5].sort{ Rand() - 0.5 } ==> [1, 5, 0, 3, 4, 2 ] # random
[1, 5, 0, 3, 4, 2 ][ 0..2 ] ==> [1, 5, 0 ]
この質問が最初に回答された時点(2008年9月)のことは、言及する価値があります Array#shuffle
は利用できなかったか、私にはまだ知られていないため、 Array#sort
その結果、これに対する編集の提案が大量にあります。
そう:
.sort{ Rand() - 0.5 }
より良いことができ、現代で短く表現できるRubyを使用した実装
.shuffle
さらに、
[0..x]
Array#take
として:
.take(x)
したがって、現代のRuby=で乱数列を生成する最も簡単な方法は次のとおりです。
(0..50).to_a.shuffle.take(x)
速度についてのアイデアを与えるために、私はこれの4つのバージョンを実行しました。
それらはすべて小規模で高速であるため、1,000,000個の数値のリストを作成するように依頼しました。時間は秒単位です:
そして、いいえ、最後の1つはタイプミスではありません。だからあなたがスピードを気にしていて、数値が0から何までの整数であっても問題ないなら、私の正確なコードは:
a = (0...1000000).sort_by{Rand}
Ruby 1.9は、要素、または配列からランダムに選択された要素を返すArray#sampleメソッドを提供します。 #sampleの結果には、同じ配列要素が2回含まれません。
(1..999).to_a.sample 5 # => [389, 30, 326, 946, 746]
to_a.sort_by
アプローチと比較すると、sample
メソッドは大幅に高速であるように見えます。簡単なシナリオでは、sort_by
をsample
と比較して、次の結果を得ました。
require 'benchmark'
range = 0...1000000
how_many = 5
Benchmark.realtime do
range.to_a.sample(how_many)
end
=> 0.081083
Benchmark.realtime do
(range).sort_by{Rand}[0...how_many]
end
=> 2.907445
はい、これはループなしで、どの番号が選択されているかを追跡することなく行うことができます。これは線形フィードバックシフトレジスタと呼ばれます。 繰り返しのない乱数列を作成
これの遊びはいかがですか? SetまたはHashを使用する必要のない一意の乱数。
x = 0
(1..100).map{|iter| x += Rand(100)}.shuffle
ハッシュを使用して、これまでに使用した乱数を追跡できます。
seen = {}
max = 100
(1..10).map { |n|
x = Rand(max)
while (seen[x])
x = Rand(max)
end
x
}
アイテムをリスト/配列に追加するのではなく、セットに追加します。
可能な乱数の有限なリスト(つまり、1から100)がある場合、ケントの解は適切です。
それ以外の場合は、ループせずにそれを行うための他の良い方法はありません。問題は、重複が発生した場合にループを実行する必要があることです。私のソリューションは効率的でなければならず、ループは配列のサイズを超えてはなりません(つまり、20個の一意の乱数が必要な場合、平均で25回の反復が必要になる場合があります)。反復回数は、数値が増えるほど悪くなります必要とより小さな最大です。以下は、上記のコードを変更して、特定の入力に必要な反復回数を示すものです。
require 'set'
def Rand_n(n, max)
randoms = Set.new
i = 0
loop do
randoms << Rand(max)
break if randoms.size > n
i += 1
end
puts "Took #{i} iterations for #{n} random numbers to a max of #{max}"
return randoms.to_a
end
必要に応じて、このコードをArray.mapのようなLOOKに記述できます。
この方法ではループはありません
Array.new(size) { Rand(max) }
require 'benchmark'
max = 1000000
size = 5
Benchmark.realtime do
Array.new(size) { Rand(max) }
end
=> 1.9114e-05
上記のKent Fredricのソリューションに基づいて、これは私が最終的に使用したものです:
def n_unique_Rand(number_to_generate, Rand_upper_limit)
return (0..Rand_upper_limit - 1).sort_by{Rand}[0..number_to_generate - 1]
end
ケント、ありがとう。
ケントのアプローチを使用すると、制限された範囲内のすべての値を維持する任意の長さの配列を生成することが可能です。
# Generates a random array of length n.
#
# @param n length of the desired array
# @param lower minimum number in the array
# @param upper maximum number in the array
def ary_Rand(n, lower, upper)
values_set = (lower..upper).to_a
repetition = n/(upper-lower+1) + 1
(values_set*repetition).sample n
end
別の、おそらくより効率的な、同じケントの 別の答え から変更された方法:
def ary_Rand2(n, lower, upper)
v = (lower..upper).to_a
(0...n).map{ v[Rand(v.length)] }
end
puts (ary_Rand 5, 0, 9).to_s # [0, 8, 2, 5, 6] expected
puts (ary_Rand 5, 0, 9).to_s # [7, 8, 2, 4, 3] different result for same params
puts (ary_Rand 5, 0, 1).to_s # [0, 0, 1, 0, 1] repeated values from limited range
puts (ary_Rand 5, 9, 0).to_s # [] no such range :)
最大値を事前に知っておくと便利ですが、次の方法で行うことができます。
class NoLoopRand
def initialize(max)
@deck = (0..max).to_a
end
def getrnd
return @deck.delete_at(Rand(@deck.length - 1))
end
end
この方法でランダムデータを取得できます。
aRndNum = NoLoopRand.new(10)
puts aRndNum.getrnd
nil
は、すべての値がデッキから排出されるときに取得します。
ここに1つの解決策があります:
これらの乱数をr_min
とr_max
の間にしたいとします。リストの各要素について、乱数r
を生成し、list[i]=list[i-1]+r
を作成します。これにより、単調増加する乱数が得られ、一意性が保証されます
r+list[i-1]
はオーバーフローしないr
> 0最初の要素には、r_min
の代わりにlist[i-1]
を使用します。完了したら、リストをシャッフルして、要素が明確に順序付けられないようにすることができます。
このメソッドの唯一の問題は、r_max
を超えても、生成する要素がまだある場合です。この場合、r_min
とr_max
を、すでに計算した2つの隣接する要素にリセットして、単にプロセスを繰り返すことができます。これは、すでに使用されている数値がない間隔で同じアルゴリズムを効果的に実行します。リストを作成するまで、これを続けることができます。