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

アフィリエイト広告を利用しています。
QRコード
【QRコード】PC<-->スマホの切り替えにご利用ください
アイキャッチ画像
運営者・ポテ

いつもありがとうございます。

ノンプログラマー向け「Excelマクロ・VBAワンポイントテクニック解説シリーズ」へようこそ。

本稿では「リストから要素をランダムに選択する方法」を解説いたします。

Information
  • ノンプログラマー
    プログラミングを専門にしていない人たちのことです。
  • VBAとマクロの違い
    VBAは、Visusal Basic for Application の略で、プログラミング言語のことです。マクロは、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関数が毎回異なる乱数列を生成し、ランダム性が高い動作を実現します。シード値を設定しない場合、乱数列が固定され、ファイルを開くたびに同じ結果が繰り返されます。

Information

シード値
乱数を生成する際の初期値のことです。乱数生成器は、このシード値をもとに計算を行い、疑似乱数を生成します。シード値が同じ場合、生成される乱数列も同じになります。そのため、異なる乱数列を得るには、シード値を毎回異なる値に設定する必要があります

    ' フィッシャー・イェーツ法でシャッフル:
    ' 配列の最後の要素から順に、ランダムに選んだ別の要素と入れ替えて固定する
    ' 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要素を出力しています。

運営者・ポテ

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

おわりに

運営者・ポテ

ご覧いただきありがとうございました。

今回の記事では、「リストから要素をランダムに選択する方法」を解説いたしました。

お問い合わせやご要望等ございましたら、「お問い合わせ/ご要望」またはコメントにて、ご連絡いただければ幸いでございます。

皆様の人生がより一層素晴らしいものになるよう、少しでもお役に立てれば幸いでございます。

なお、当サイトでは様々な情報を発信しております。もしよろしければ、トップページもご覧いただけると幸いでございます。


関連記事

本稿と関連の深い記事です。もしよろしければ、合わせてご活用ください。

VBAプログラミングスキルアップのための参考情報

ここでは参考図書を紹介いたしますが、これらに限らず自分に合うものを選ぶことが重要だと考えております。皆様の、より一層のご成功を心よりお祈りしております。

VBAプログラミングのスキルアップ

学習用としてもハンドブックとしても役立つ便利な書籍がこちらです。価格はやや高めですが、その内容は非常に充実しています。相応のスキルを身に付けるためには、こうしたしっかりとした書籍を一冊持っておくと良いでしょう。



入門書に関しては、どの書籍も大きな違いはありません。あまり迷うことに時間をかけるよりは、手頃なものを一冊選んでみると良いでしょう。VBAの入門書は数多く出版されていますので、興味がある方はぜひチェックしてみてください。

甲乙つけがたい場合、私はインプレス社の「いちばんやさしい」シリーズを選ぶことが多いです。

\チェックしてみよう/

\チェックしてみよう/

\チェックしてみよう/


VBAのプログラミング能力を客観的に証明したい場合には「VBAエキスパート試験」があります。この試験はVBAの知識を公式に認定するものです。VBAの総合的な能力獲得を目指す方に適しています。以下の公式テキストが販売されております。



プログラミングの一般教養

「独学プログラマー」というプログラミングの魅力を解説した書籍があります。これはVBAではなくPythonを題材としていますが、プログラミングの基本的な知識や思考法、仕事の進め方まで幅広く学べます。


こちらの記事でも紹介しております。もしよろしければご覧ください。

QRコード
【QRコード】PC<-->スマホの切り替えにご利用ください

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です