【VBA】重複しないでランダムに抜き出す
今回はあるデータセットから、複数データを重複しないでランダムに抜き出す VBA マクロを作ってみます。まずその練習として、4変数配列を用意して”A”, “B”, “C”, “D” という文字列を格納できる Sub プロシージャを作っておきます。
Option Base 1 Sub Sorting() Dim i As Integer, rd As Integer Dim x As String Dim mydata(4) As String mydata(1) = "A" mydata(2) = "B" mydata(3) = "C" mydata(4) = "D" For i = 1 To 4 Randomize '1~ 4の整数を得ます rd = Int(4 * RND + 1) 'xに元のデータを保存しておきます x = mydata(i) '配列データを他の配列データと交換します mydata(i) = mydata(rd) '保存しておいたデータを交換先に入れます mydata(rd) = x Next i '配列データを並べます For i = 1 To 4 Debug.Print mydata(i); Next i End Sub
Sorting() を実行するたびに、イミディエイトウィンドウに CDBA, ACDB などが無作為に表示されます。要となるのは
x = mydata(i)
という部分です。mydata(i) と mydata(rd) の間で直接データの交換はできないので、いったん x という変数を中継して交換を実行しています。言われてみれば簡単なんだけど、こばとは全然思いつかなかったので、こちらのサイト を参考にさせていただきました。どうもありがとうございます。
というわけで、この配列交換プロシージャを応用して、あるリストから無作為に複数データを重複なしで抜き出すマクロを作ってみました。まずは 10 個のデータを用意してください。適当なのがなければ下のデータをコピーしてね。
| 名簿 |
|---|
| 玉国 慧之輔 |
| 稲嶺 喜弘 |
| 谷河 史生 |
| 愛発 行泰 |
| 葛島 須美恵 |
| 茶円 康美 |
| 東福寺 裕吾 |
| 南畑 安枝 |
| 井土 美智江 |
| 武枝 威和夫 |
コピーしたデータはセル B2 にぺったんこと貼りつけてくださいな。それではマクロを書いてみましょう。
'[VBA] 複数データを重複なしでランダムに抜き出す Option Base 1 Sub Random_choice() Dim i As Integer, rd As Integer Dim x As String '10 個の要素をもつ配列を文字列型で宣言しておきます Dim mydata(10) As String 'B3 から B12 のデータを配列に入れます For i = 1 To 10 mydata(i) = ActiveSheet.Cells(i + 2, 2) Next i '配列データを無作為に交換します For i = 1 To 10 Randomize rd = Int(10 * RND + 1) x = mydata(i) mydata(i) = mydata(rd) mydata(rd) = x Next i 'D3~D5 に mydata(1)~mydata(3)を書き込みます For i = 3 To 5 ActiveSheet.Cells(i, 4) = mydata(i) Next i End Sub
Random_choice() を実行すると下の図のようにランダムに 3 人が選び出されますよ。

データをテーブル形式に変えておけば、より汎用性の高いマクロを作ることができます。[ホーム] ⇒ [テーブルとして書式設定]から 名簿データをテーブルに変えて、[テーブルツール] でテーブル名を「名簿」としてください。同じようにして選出データも「選出」というテーブルにしておきます。それから次のようなコードを書いてみましょう。
'[VBA] テーブルから重複しないでランダムに抜き出すマクロ
Option Base 1
Sub Random_choice_table()
Dim i As Integer, ct As Integer, rd As Integer
Dim x As String
Dim mylist As ListObject
Dim outrange As Range
Dim mydata() As String
Set mylist = ActiveSheet.ListObjects("名簿")
Set listrange = ActiveSheet.ListObjects("名簿").DataBodyRange
Set outrange = ActiveSheet.ListObjects("選出").DataBodyRange
'名簿のデータ数を数えます
ct = mylist.ListRows.Count
'配列の要素数を決めます
ReDim mydata(ct)
'配列に名簿のデータを放り込みます
For i = 1 To ct
mydata(i) = listrange.Cells(i, 1)
Next i
'配列データをシャッフルします
For i = 1 To ct
Randomize
rd = Int(ct * RND + 1)
x = mydata(i)
mydata(i) = mydata(rd)
mydata(rd) = x
Next i
For i = 1 To 3
outrange.Cells(i, 1) = mydata(i)
Next i
End Sub
Random_choice_table() の実行結果は先ほどと同じようになります。

Random_choice_table() は(名簿をテーブル形式にしておけば)データ数がいくつであっても使えます。InputBox 関数なんかを使ってちょこっと改造すると、抜き出す人数もユーザーさんが入力できるようになります。掃除当番や班を決める時にも使えますよ。
コメント