【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 関数なんかを使ってちょこっと改造すると、抜き出す人数もユーザーさんが入力できるようになります。掃除当番や班を決める時にも使えますよ。
  
  
  
  
コメント