TGWS>プログラミング>

ランダムセレクト

よくある普通の/合計数がわからない場合/確率に偏りがある場合

よくある普通の

例えば次のように大きさのわかっている配列があってその中から一つを選ぶという場合などです。

Dim A(1 To 10) As String
A(1) = "First"
A(2) = "Second"
A(3) = "Third"
A(4) = "Fourth"
A(5) = "Fifth"
A(6) = "Sixth"
A(7) = "Seventh"
A(8) = "Eighth"
A(9) = "Ninth"
A(10) = "Tenth"
Debug.Print A(Int(Rnd * (UBound(A) - LBound(A) + 1) + LBound(A)))

まあ、別に特別なことはしていない、乱数として基本的な使い方です。

合計数がわからない場合

例えばファイルからデータを読み込みつつその中から1つだけランダムにデータを取り出す場合です。

Dim Text As String, Selected As String
Dim I As Integer
Open FileName For Input As #1
Do Until EOF(1)
    Line Input #1, Text
    I = I + 1
    If Rnd * I < 1 Then Selected = Text
Loop
Debug.Print Selected

解説しますと、まず最初の行が読み込まれると、Selectedは1分の1の確率で今の行のデータになります。
そして次の行を読み込むと2分の1の確率で2行目のデータになり、残り2分の1の確率で1行目のデータのままです。
更に3行目を読み込むと3分の1の確率で3行目のデータになって、残り3分の2を前の2行分で分け合って、3つとも均等な確立で選ばれることになります。
これを繰り返していくと、どの行も同じ確率で選ばれるようになるわけです。

これ、予め合計数を調べて配列に読み込んでからさっきのような選び方をすればよさそうにも見えますが、新しく配列を作るのが大変な場合もありますし、簡単に次のような応用ができたりします。

確率に偏りがある場合

さいころってのは安物だと5の目が微妙に出やすいそうです。
そういう場合に限らず、確率ってのは現実的にはどこかに偏る場合が多いです。
というわけで、それぞれの項目の選ばれる確率が一定でない場合なんかも考えてみます。
そのためにはまずデータごとに対応する確率のデータも必要になってくるのですが、今回は文字数をそのままそのデータの出やすさとして使うことにします。

Dim Text As String, Selected As String
Dim I As Integer, N As Integer
Open FileName For Input As #1
Do Until EOF(1)
    Line Input #1, Text
    N = Len(Text)
    I = I + N
    If Rnd * I < N Then Selected = Text
Loop
Debug.Print Selected

で、整数に限らずNをいろんな値にすると選ばれる確率を操作できるわけです。
当然ながら、Nという数値は実際の確率ではなく確率の偏り具合なので、合計が100%になる必要は全くありません。

サンプル