36

これは私がこれまでに持っているものです:

myArray.map!{ rand(max) }

ただし、明らかに、リスト内の番号が一意でない場合があります。より大きなリストを作成せずに、リストに一意の番号のみが含まれていることを確認するにはどうすればよいですか。リストからn個の一意の番号を選択するだけです。

編集:
可能であれば、ループなしでこれが行われることを本当に望んでいます。

4

15 に答える 15

65
(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 }

を使用して現代のルビーの実装でより良く、より短く表現することができます

.shuffle

さらに、

[0..x]

より明確に次のように書くことができますArray#take

.take(x)

したがって、現代のルビーで一連の乱数を生成する最も簡単な方法は次のとおりです。

(0..50).to_a.shuffle.take(x)
于 2008-09-23T05:10:08.303 に答える
25

これはセットを使用します:

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
于 2008-09-23T04:36:53.173 に答える
23

Ruby 1.9 では、配列からランダムに選択された要素、または要素を返す Array#sample メソッドが提供されています。#sample の結果には、同じ Array 要素が 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
于 2012-03-27T03:03:25.643 に答える
22

速度についてのアイデアを提供するために、これの 4 つのバージョンを実行しました。

  1. ライアンの提案のように、セットを使用します。
  2. 必要よりも少し大きい配列を使用してから、uniq! を実行します。最後に。
  3. カイルが提案したように、ハッシュを使用します。
  4. ケントの提案のように、必要なサイズの配列を作成し、ランダムに並べ替えます(ただし、何もしない余分な「-0.5」はありません)。

小さいスケールではどれも高速なので、それぞれに 1,000,000 個の数字のリストを作成してもらいました。秒単位の時間は次のとおりです。

  1. セット: 628
  2. 配列 + 一意: 629
  3. ハッシュ: 645
  4. 固定配列 + 並べ替え: 8

いいえ、最後のものはタイプミスではありません。したがって、速度を気にし、数値が 0 から任意の整数であっても問題ない場合、私の正確なコードは次のとおりです。

a = (0...1000000).sort_by{rand}
于 2008-09-23T17:25:58.113 に答える
4
[*1..99].sample(4) #=> [64, 99, 29, 49]

Array#sampleドキュメントによると、

要素は、ランダムで一意のインデックスを使用して選択されます

必要な場合SecureRandom(疑似乱数の代わりにコンピューター ノイズを使用します):

require 'securerandom'

[*1..99].sample(4, random: SecureRandom) #=> [2, 75, 95, 37]
于 2020-05-18T04:38:51.267 に答える
4

はい、ループなしで、どの番号が選択されたかを追跡せずにこれを行うことができます。これは線形フィードバック シフト レジスタと呼ばれます: 繰り返しのない乱数シーケンスの作成

于 2010-11-02T15:18:49.670 に答える
2

これで遊んでみてはどうですか?Set や Hash を使用する必要のない一意の乱数。

x = 0
(1..100).map{|iter| x += rand(100)}.shuffle
于 2008-09-24T07:03:49.800 に答える
1

ハッシュを使用して、これまでに使用した乱数を追跡できます。

seen = {}
max = 100
(1..10).map { |n|
  x = rand(max)
  while (seen[x]) 
    x = rand(max)
  end
  x
}
于 2008-09-23T04:24:26.527 に答える
1

アイテムをリスト/配列に追加するのではなく、セットに追加します。

于 2008-09-23T04:24:49.037 に答える
1

上記の 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

ありがとうケント。

于 2012-01-16T05:00:38.093 に答える
1

この方法ではループはありません

Array.new(size) { rand(max) }

require 'benchmark'
max = 1000000
size = 5
Benchmark.realtime do
  Array.new(size) { rand(max) }
end

=> 1.9114e-05 
于 2015-09-03T08:38:12.157 に答える
1

可能性のある乱数 (つまり 1 から 100) のリストが有限である場合、Kent の解は適切です。

そうでなければ、ループせずにそれを行う良い方法は他にありません。問題は、重複を取得した場合にループを実行する必要があることです。私のソリューションは効率的であり、ループは配列のサイズを超えてはなりません (つまり、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 のように見えるように書くこともできます:)

于 2008-09-23T06:41:42.857 に答える
0

ここに1つの解決策があります:

これらの乱数を ~ の間にするr_minとしr_maxます。リスト内の各要素に対して、乱数を生成し、rmake しlist[i]=list[i-1]+rます。これにより、単調に増加する乱数が得られ、一意性が保証されます。

  • r+list[i-1]オーバーフローしない
  • r> 0

最初の要素には、r_min代わりにlist[i-1]. 完了したら、リストをシャッフルして、要素がそれほど明確に順番に並んでいないようにすることができます。

この方法の唯一の問題は、r_max生成する要素がまだ残っている場合です。この場合、計算済みの隣接する 2 つの要素にリセットr_minして、プロセスを繰り返すだけです。r_maxこれにより、すでに使用されている数値がない間隔で同じアルゴリズムが効果的に実行されます。リストにデータが入力されるまで、これを続けることができます。

于 2008-09-23T04:44:39.753 に答える
0

方法 1

Kent のアプローチを使用すると、すべての値を制限された範囲に保ちながら、任意の長さの配列を生成できます。

# 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

方法 2

同じケントの別の回答から変更された、おそらくより効率的な別の方法:

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 :)
于 2012-10-19T13:46:43.357 に答える
0

最大値を事前に知っておくと便利な場合は、次の方法で実行できます。

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すべての値がデッキから排出されるときに取得します。

于 2008-09-23T12:25:28.180 に答える