【簡単エクセル/Excel VBA マクロ】リストから要素をランダムに選択する方法|フィッシャー・イェーツのシャッフル|ワンポイントテクニック #007



いつもありがとうございます。
ノンプログラマー向け「Excelマクロ・VBAワンポイントテクニック解説シリーズ」へようこそ。
本稿では「リストから要素をランダムに選択する方法」を解説いたします。
データ処理において「ランダム性」が求められる場面は意外と多いものです。例えば、アンケート回答のランダム抽出や、商品リストのランダム表示、さらにはチームメンバーのランダムな組み分けなどです。
では、「ランダム選択」を行うにはどうすれば良いのでしょうか?
そこで登場するのが「フィッシャー・イェーツのシャッフル」です。この手法をVBAで実装することで、要素の順序をランダムに並べ替えることが可能です。
今回紹介するテクニックを使えば、あなたのVBAマクロが一段とプロフェッショナルな仕上がりになるでしょう。
VBAを活用して、自分やコミュニティに合ったアプリを作成し、仕事量は半分に、成果は2倍にしていきましょう!初心者の方にも分かりやすく丁寧に解説していきますので、ぜひ最後までご覧ください。
リストから要素をランダムに選択する方法|フィッシャー・イェーツのシャッフル

シナリオ
1週間の曜日(日、月、火、水、木、金、土)7つの中から、ランダムに3つを選びます。
具体例と解説
百聞は一見に如かず。まずは、上述のシナリオを実現するコードと、その実行結果を示します。
コードは以下の通りです。
Option Explicit ' 変数宣言の強制(タイプミスや意図しないデータ型の使用を防止)
Sub SelectRandomly()
' 変数の宣言
Dim days_array() As Variant ' 1週間の曜日を格納する配列
Dim current_index As Long ' 現在の配列インデックス
Dim random_index As Long ' ランダムに選ばれたインデックス
Dim swapping_day As String ' 入れ替え用に記録する一時的な曜日
' 配列に1週間分の曜日を設定
days_array = Array("日", "月", "火", "水", "木", "金", "土")
' シード値を初期化
Randomize
' フィッシャー・イェーツ法でシャッフル:
' 配列の最後の要素から順に、ランダムに選んだ別の要素と入れ替えて固定する
' UBound=6、LBound=0
For current_index = UBound(days_array) To LBound(days_array) Step -1
' LBound~current_indexの範囲(未処理の範囲)でRnd関数を使用して
' ランダムなインデックスを生成:
' Int関数:小数点以下を切り捨て整数部分を返す 例)Int(5.9)→5、Int(0.999)→0
' Rnd関数:0.0 以上 1.0 未満の乱数を返す 例)0.123, 0.999, 0.456 など
random_index = Int( _
(current_index - LBound(days_array) + 1) * Rnd _
) + LBound(days_array)
' 現在の要素(current_index)とランダムに選んだ要素(random_index)を交換:
' 現在の要素を一時的な変数に保存(上書きを防ぐため)
swapping_day = days_array(current_index)
' 現在の位置(インデックス)にランダムに選んだ要素を代入
days_array(current_index) = days_array(random_index)
' 一時的に保存していた現在の要素をランダムな位置に代入して交換
' ※これをしないと要素が重複する
days_array(random_index) = swapping_day
Next current_index
' シャッフル後の最初の3要素を出力
Debug.Print "ランダムに選ばれた3要素:"
For current_index = LBound(days_array) To LBound(days_array) + 2
Debug.Print days_array(current_index)
Next current_index
End Sub
このコードを実行するとイミディエイトウィンドウに以下のような結果が出力されます。毎回結果は異なります。
実行1回目:
ランダムに選ばれた3要素:
日
月
金
実行2回目:
ランダムに選ばれた3要素:
水
火
土
実行3回目:
ランダムに選ばれた3要素:
水
金
日

解説していきます。
Option Explicit ' 変数宣言の強制(タイプミスや意図しないデータ型の使用を防止)
ここでは、Option Explicit
を有効にしています。この設定を使うと、変数を使用する前に必ず宣言が必要になります。これにより、変数のタイプミスや未定義変数によるエラーを防ぎ、コードの安全性と信頼性を高めることができます。
' 変数の宣言
Dim days_array() As Variant ' 1週間の曜日を格納する配列
Dim current_index As Long ' 現在の配列インデックス
Dim random_index As Long ' ランダムに選ばれたインデックス
Dim swapping_day As String ' 入れ替え用に記録する一時的な曜日
ここでは、コード内で使用する変数が宣言されています。変数は Dim 変数名 As データ型
の構文で宣言します。これにより、各変数は As
以降で指定したデータ型のデータを格納できるようになります。
なお、各データ型の意味は下表の通りです。
データ型 | 種類 | 意味 |
---|---|---|
Long |
数値型 | -2,147,483,648 から 2,147,483,647 までの範囲の整数を格納できる数値型のデータ型です。 |
Variant |
汎用型 | 任意のデータ型を格納できる柔軟なデータ型です。ここでは配列などに使用されています。 |
String |
文字列型 | テキスト情報を格納する文字列型のデータ型です。 |
' 配列に1週間分の曜日を設定
days_array = Array("日", "月", "火", "水", "木", "金", "土")
ここでは、1週間の曜日を配列に設定しています。この配列を後のシャッフル処理でランダムに並び替えます。なお、Array関数を使用しており、要素数が明確であるため、配列のサイズ調整をする必要(Redim
をする必要)はありません。
' シード値を初期化
Randomize
ここでは、Randomize
を使用して乱数生成器のシード値を現在の時刻に基づいて設定しています。この設定により、Rnd
関数が毎回異なる乱数列を生成し、ランダム性が高い動作を実現します。シード値を設定しない場合、乱数列が固定され、ファイルを開くたびに同じ結果が繰り返されます。
' フィッシャー・イェーツ法でシャッフル:
' 配列の最後の要素から順に、ランダムに選んだ別の要素と入れ替えて固定する
' UBound=6、LBound=0
For current_index = UBound(days_array) To LBound(days_array) Step -1
' LBound~current_indexの範囲(未処理の範囲)でRnd関数を使用して
' ランダムなインデックスを生成:
' Int関数:小数点以下を切り捨て整数部分を返す 例)Int(5.9)→5、Int(0.999)→0
' Rnd関数:0.0 以上 1.0 未満の乱数を返す 例)0.123, 0.999, 0.456 など
random_index = Int( _
(current_index - LBound(days_array) + 1) * Rnd _
) + LBound(days_array)
' 現在の要素(current_index)とランダムに選んだ要素(random_index)を交換:
' 現在の要素を一時的な変数に保存(上書きを防ぐため)
swapping_day = days_array(current_index)
' 現在の位置(インデックス)にランダムに選んだ要素を代入
days_array(current_index) = days_array(random_index)
' 一時的に保存していた現在の要素をランダムな位置に代入して交換
' ※これをしないと要素が重複する
days_array(random_index) = swapping_day
Next current_index
ここでは、配列をランダムに並べ替えるためにフィッシャー・イェーツシャッフルを実装しています。
ランダムに選ばれたインデックス同士で要素を入れ替えていくことで、重複することなくシャッフルが実現されています。ループが進むにつれて、未処理の部分(未シャッフルの部分)が少しずつ減っていくため、シャッフルが終了した時点で配列の要素は完全にランダムな順番に並び替えられます。
この方法を使うことで、配列の要素を効率よく、かつ公平にシャッフルすることができます。
' シャッフル後の最初の3要素を出力
Debug.Print "ランダムに選ばれた3要素:"
For current_index = LBound(days_array) To LBound(days_array) + 2
Debug.Print days_array(current_index)
Next current_index
ここでは、シャッフル後の配列から最初の3要素を出力しています。

以上で解説は終了です。ありがとうございました。
おわりに


ご覧いただきありがとうございました。
今回の記事では、「リストから要素をランダムに選択する方法」を解説いたしました。
お問い合わせやご要望等ございましたら、「お問い合わせ/ご要望」またはコメントにて、ご連絡いただければ幸いでございます。
皆様の人生がより一層素晴らしいものになるよう、少しでもお役に立てれば幸いでございます。
なお、当サイトでは様々な情報を発信しております。もしよろしければ、トップページもご覧いただけると幸いでございます。
関連記事
本稿と関連の深い記事です。もしよろしければ、合わせてご活用ください。
- 【簡単エクセル/Excel VBA マクロ】Excel VBA マクロの全体像 | みんなの実用学 (jitsuyogaku.com)
- 【簡単エクセル/Excel VBA マクロ】通常使用編目次 | みんなの実用学 (jitsuyogaku.com)
- 【簡単エクセル/Excel VBA マクロ】ワンポイントテクニック編目次 | みんなの実用学 (jitsuyogaku.com)
- 【簡単エクセル/Excel VBA マクロ】アプリ事例編目次 | みんなの実用学 (jitsuyogaku.com)
VBAプログラミングスキルアップのための参考情報
ここでは参考図書を紹介いたしますが、これらに限らず自分に合うものを選ぶことが重要だと考えております。皆様の、より一層のご成功を心よりお祈りしております。
VBAプログラミングのスキルアップ
学習用としてもハンドブックとしても役立つ便利な書籍がこちらです。価格はやや高めですが、その内容は非常に充実しています。相応のスキルを身に付けるためには、こうしたしっかりとした書籍を一冊持っておくと良いでしょう。
入門書に関しては、どの書籍も大きな違いはありません。あまり迷うことに時間をかけるよりは、手頃なものを一冊選んでみると良いでしょう。VBAの入門書は数多く出版されていますので、興味がある方はぜひチェックしてみてください。
甲乙つけがたい場合、私はインプレス社の「いちばんやさしい」シリーズを選ぶことが多いです。
\チェックしてみよう/
\チェックしてみよう/
\チェックしてみよう/
VBAのプログラミング能力を客観的に証明したい場合には「VBAエキスパート試験」があります。この試験はVBAの知識を公式に認定するものです。VBAの総合的な能力獲得を目指す方に適しています。以下の公式テキストが販売されております。
プログラミングの一般教養
「独学プログラマー」というプログラミングの魅力を解説した書籍があります。これはVBAではなくPythonを題材としていますが、プログラミングの基本的な知識や思考法、仕事の進め方まで幅広く学べます。
こちらの記事でも紹介しております。もしよろしければご覧ください。
