ランダムな配列の必要性

通常、配列はなんらかの規則性を持って並んでいることが多いのですが、並び順が不規則であることが必要な場合があります。データの最大や最小や昇順や降順などを無視した状態でのテストを行うような場合で、データがいくつあるか不明、最大値も不明、最小値も不明、でもそこから結果がどうなるのかを検証しなければならない、というようなことがあります。

そのような場合には規則性を持ったデータ列はむしろ邪魔で、めちゃくちゃな並び順であることの方が必要になります。手で入れ替えてもいいのですが、数が多くなれば当然大変です。

以下で配列の内容を値に関係なく偏りなくランダムに並べ替えるコードを紹介します。

処理速度はO(n)と高速に動作するフィッシャー-イェーツのシャッフルアルゴリズムを採用しています。当該アルゴリズムについての詳細は各自で。

コード

以下は配列の要素を高速にランダムに入れ替える関数です。引数には配列を渡します。

処理の開始時に引数配列の要素数を取得し、要素が1つしかない場合は入れ替える必要がないため関数を抜けます。

引数の配列のデータ型はなんでもOKにしたいので、先にデータ型を取得しています。なお、IsObject(ar)と書いてしまうと要素ではなく配列自体の型をとってVariant型と判定されて常にFalse扱いになるため、IsObject(ar(0))として配列の要素でデータ型の判定を行っています。

メインのループ部分ですが、一般的な配列ループは先頭から終端に向かいますが、逆に終端から先頭に向かってループしています。これは2つの理由があり、一つはアルゴリズムのルールに従っていることと、乱数値を取得する際の終端値をループごとに1ずつ減らす必要があるのに都合が良かったためです。

同じことを先頭から終端に向かって行うループ(逆順でのループ)でもできますが、(考えるのが面倒だったので)やりませんでした。

ループ内ではループごとに0から配列インデックスの終端値の範囲でRnd関数を使って整数値を取得し、配列のインデックスに利用します。

Rnd関数や乱数については「VBAで乱数を発生させる(Rnd、Randomize)」をご参照ください。

あとは、取得した乱数値と配列の終端インデックスの要素を入れ替えます。

使い方

上の関数の使い方です。配列作って呼び出すだけです。

String型の配列とRange型の配列を用意してそれぞれで実行します。

実行結果(実行するたびに並び順は変わります)
0 – a
1 – c
2 – d
3 – e
4 – b
5 – g
6 – h
7 – f
0 – A1
1 – A6
2 – A8
3 – A7
4 – A5
5 – A4
6 – A3
7 – A2