■解答例
流れとしては、配列にn人分の要素スペースを作って
シャッフルしてm人分を取り出すだけの簡単なお仕事ですね。
シャッフルは、Fisher-Yatesを使いました。
最終的なコードはこちら→最終的なコード
■Fisher-Yatesアルゴリズムを使ってみる
Fisher-Yatesアルゴリスムとは・・・
配列の一番最後の要素とそれより前の要素群の中から乱数で一つ選び入れ入替える。
そして、配列の要素を一つ前に移動して上記を繰り返すことで入替える。
例えば5つの要素をもった配列があったとします
1サイクル目--------------------------------------------------------------
最後の要素(5)とそれより前(1,2,3,4)の要素から乱数で一つ数字を選びます
乱数で選ばれた数字(ここでは2)と入替をします。
2サイクル目--------------------------------------------------------------
一つ前の要素(4)とそれより前(1,5,3)の要素から乱数で一つ数字を選びます
乱数で選ばれた数字(ここでは1)と入替をします。
3サイクル目--------------------------------------------------------------
一つ前の要素(3)とそれより前(4,5)の要素から乱数で一つ数字を選びます
乱数で選ばれた数字(ここでは5)と入替をします。
4サイクル目--------------------------------------------------------------
1番目と2番目の要素を入れ替えます
では、コードです。
モジュール名:SubModule
4行目:抽選に使うn人分の要素を持った配列を作るためlistを宣言する
5行目:配列の要素を確定する
7~9行目:For分で各要素に抽選番号替わりの数字を格納する
12行目:配列の要素をシャッフルする自作関数。
引数は、参照渡しで渡しています
15行目:当選者を格納する配列用の変数を宣言
16行目:要素数を定義
17~19行目:m人当選するのでlistの最初の要素からm番目までをresult変数に取り出す
21行目:取り出した値を格納しているresult変数を返す
モジュール名:CommonModule
配列の要素が大量にある場合、値渡しで受け取るより参照渡しで
やりとりしたほうが効率的なので、参照渡しにしています。
3行目:配列を参照渡しでうけとります。
4行目:乱数を使うのでRandomizeで乱数の初期化します。
5行目:配列のインデックス用にi変数、
配列の2要素を入れ替えるようにtemp変数
乱数を格納するようにRandNum変数を宣言
6行目:For文で一番最後の要素から2番目の要素までループさせる
7行目:乱数でi番目より前の要素から一つ選ぶ
8行目:同時に2要素を入れ替えれないので、乱数で選んだ要素の値を一時退避する
9行目:乱数で選ばれた要素にi番目の要素を複製する
10行目:i番目の要素に一時退避していた乱数で選んだ要素の値を複製する
11行目:繰り返し
実際にこんな感じで使う
モジュール名:MainModule
実行結果
以下に最終的なコードを示しておきます
モジュール名:SubModule
モジュール名:CommonModule
流れとしては、配列にn人分の要素スペースを作って
シャッフルしてm人分を取り出すだけの簡単なお仕事ですね。
シャッフルは、Fisher-Yatesを使いました。
最終的なコードはこちら→最終的なコード
■Fisher-Yatesアルゴリズムを使ってみる
Fisher-Yatesアルゴリスムとは・・・
配列の一番最後の要素とそれより前の要素群の中から乱数で一つ選び入れ入替える。
そして、配列の要素を一つ前に移動して上記を繰り返すことで入替える。
例えば5つの要素をもった配列があったとします
1サイクル目--------------------------------------------------------------
最後の要素(5)とそれより前(1,2,3,4)の要素から乱数で一つ数字を選びます
乱数で選ばれた数字(ここでは2)と入替をします。
2サイクル目--------------------------------------------------------------
一つ前の要素(4)とそれより前(1,5,3)の要素から乱数で一つ数字を選びます
乱数で選ばれた数字(ここでは1)と入替をします。
3サイクル目--------------------------------------------------------------
一つ前の要素(3)とそれより前(4,5)の要素から乱数で一つ数字を選びます
乱数で選ばれた数字(ここでは5)と入替をします。
4サイクル目--------------------------------------------------------------
1番目と2番目の要素を入れ替えます
では、コードです。
モジュール名:SubModule
Option Explicit Function lot(n As Integer, m As Integer) As Variant Dim list As Variant, i As Integer ReDim list(n - 1) For i = 0 To n - 1 list(i) = i + 1 Next Call ArrayShuffle(list) Dim result As Variant ReDim result(m - 1) For i = 0 To m - 1 result(i) = list(i) Next lot = result End Function3行目:引数は2つ。全数であるnと抽選される人数であるm
4行目:抽選に使うn人分の要素を持った配列を作るためlistを宣言する
5行目:配列の要素を確定する
7~9行目:For分で各要素に抽選番号替わりの数字を格納する
12行目:配列の要素をシャッフルする自作関数。
引数は、参照渡しで渡しています
15行目:当選者を格納する配列用の変数を宣言
16行目:要素数を定義
17~19行目:m人当選するのでlistの最初の要素からm番目までをresult変数に取り出す
21行目:取り出した値を格納しているresult変数を返す
モジュール名:CommonModule
Option Explicit Sub ArrayShuffle(ByRef list As Variant) Randomize Dim i As Integer, temp As Integer, RandNum As Integer For i = UBound(list) To 1 Step -1 RandNum = Int(Rnd() * i) temp = list(RandNum) list(RandNum) = list(i) list(i) = temp Next End Sub参照渡しで引数を受け取ります。
配列の要素が大量にある場合、値渡しで受け取るより参照渡しで
やりとりしたほうが効率的なので、参照渡しにしています。
3行目:配列を参照渡しでうけとります。
4行目:乱数を使うのでRandomizeで乱数の初期化します。
5行目:配列のインデックス用にi変数、
配列の2要素を入れ替えるようにtemp変数
乱数を格納するようにRandNum変数を宣言
6行目:For文で一番最後の要素から2番目の要素までループさせる
7行目:乱数でi番目より前の要素から一つ選ぶ
8行目:同時に2要素を入れ替えれないので、乱数で選んだ要素の値を一時退避する
9行目:乱数で選ばれた要素にi番目の要素を複製する
10行目:i番目の要素に一時退避していた乱数で選んだ要素の値を複製する
11行目:繰り返し
実際にこんな感じで使う
モジュール名:MainModule
Option Explicit Sub main() Dim result As Variant result = lot(10, 3) Dim i As Integer For i = 0 To UBound(result) Debug.Print result(i) Next Debug.Print "-------------" End Sub
実行結果
7 4 6 ------------- 8 3 5 ------------- 7 9 1 ------------- 5 4 8 -------------
以下に最終的なコードを示しておきます
モジュール名:SubModule
Option Explicit Function lot(n As Integer, m As Integer) As Variant '### n人の中からm人を選ぶ関数 '### 引数 '### 省略不可:n…参加者全員の数を指定 '### 省略不可:m…選ばれる人数を指定 '### '### ArrayShuffle関数を必要 '######################################## Dim list As Variant, i As Integer ReDim list(n - 1) For i = 0 To n - 1 list(i) = i + 1 Next Call ArrayShuffle(list) Dim result As Variant ReDim result(m - 1) For i = 0 To m - 1 result(i) = list(i) Next lot = result End Function
モジュール名:CommonModule
Option Explicit Sub ArrayShuffle(ByRef list As Variant) '### 配列の要素をシャッフルする関数 '### 変数 '### 省略不可:list…参照渡しで配列を渡す '########################################## Randomize Dim i As Integer, temp As Integer, RandNum As Integer For i = UBound(list) To 1 Step -1 RandNum = Int(Rnd() * i) temp = list(RandNum) list(RandNum) = list(i) list(i) = temp Next End Sub
0 件のコメント:
コメントを投稿