任意のサイズの 2 次元配列に偶数の項目が含まれているとします。また、明確にするために、配列内の特定の項目として配置する 2 つのものからのみ選択できると仮定しましょう。配列内の特定のインデックスにランダムな選択肢を配置する方法はありますが、配列がいっぱいになると、2 つの選択肢が均等に分割されます。
コードで答えがある場合は、Java が優先されますが、他の言語も問題ありません。
基本的に逆に考えることができます。与えられたインデックスにどの値を入れるかを決めるのではなく、配列から n/2 要素を選択し、それらに最初の値を入れることができます。次に、2 番目の値を他の n/2 に配置します。
2 次元A[M,N]
配列はベクトルにマップできますV[M*N]
(マッピングを行うには、行優先または列優先の順序を使用できます)。
ベクトルから始めV[M*N]
ます。配列の前半を最初の選択肢で埋め、配列の後半を 2 番目の選択肢オブジェクトで埋めます。Fisher-Yatesシャッフルを実行し、シャッフルされた配列を 2 次元配列に変換します。配列は、2 つの選択肢の間で均等に分割された要素で満たされ、特定のインデックスごとの選択肢はランダムになります。
擬似コード:
int trues_remaining = size / 2;
int falses_remaining = size / 2;
while (trues_remaining + falses_remaining > 0)
{
if (trues_remaining > 0)
{
if (falses_remaining > 0)
array.push(getRandomBool());
else
array.push(true);
}
else
array.push(false);
}
ただし、実際には2つ以上の値にスケーリングすることはありません。どうですか:
assoc_array = { 1 = 4, 2 = 4, 3 = 4, 4 = 4 };
while (! assoc_array.isEmpty())
{
int index = rand(assoc_array.getNumberOfKeys());
int n = assoc_array.getKeyAtIndex(index);
array.push(n);
assoc_array[n]--;
if (assoc_array[n] <= 0) assoc_array.deleteKey(n);
}
編集:2次元配列を要求したことに気づきました。このアプローチをn次元に適応させるのは簡単なはずです。
EDIT2:上記のコメントから、「スクールヤードピック」はこれに最適な名前です。
ランダム性の要件が非常に厳しいようには思えませんが、それらの恩恵を受ける可能性のある人のために、もう少し考えを投稿したいと思いました。
あなたは基本的に疑似ランダムバイナリシーケンスを求めています、そして私が知っている最も人気のあるものは最大長シーケンスです。これは、線形フィードバックシフトレジスタとともにnビットのレジスタを使用して、完全にフラットな周波数スペクトルを持つ1と0の周期的なシリーズを定義します。少なくとも、シーケンスの周期(2 ^ n-1ビット)によって決定される特定の範囲内で完全にフラットです。
どういう意味ですか?基本的に、それは、その全長が使用される場合、シーケンスがすべてのシフト(したがって周波数)にわたって最大限にランダムであることが保証されることを意味します。乱数ジェネレーターから生成された同じ長さの数列と比較すると、通常のランダムに生成された数列よりも長さあたりのランダム性が高くなります。
このため、システムのホワイトノイズ分析でインパルス関数を決定するために使用されます。特に、実験時間が貴重で、高次の交差効果がそれほど重要でない場合に使用されます。シーケンスはそれ自体のすべてのシフトに対してランダムであるため、その自己相関は完全なデルタ関数であり(上記の修飾子を除く)、刺激が刺激と応答の間の相互相関を汚染することはありません。
このマトリックスのアプリケーションが何であるかはわかりませんが、単にランダムに「表示」する必要がある場合は、これで非常に効果的になります。1と0のバランスが取れているという点で、シーケンスは0よりも1だけ多いことが保証されています。したがって、2 ^ nのグリッドを作成しようとしている場合は、タックすることで正しい結果が得られることが保証されます。最後に0。
したがって、m系列は、乱数ジェネレーターを使用して生成するものよりもランダムであり、0と1の数が定義されています。ただし、任意のサイズの2d行列を無条件に生成することはできません。グリッド内の要素の総数が2の累乗である場合のみです。
以下はList<T>
、マトリックスの領域のサイズを作成し、半分を最初の選択肢 ( spaces[0]
) で埋め、半分を 2 番目の選択肢 ( ) で埋めspaces[1]
ます。その後、シャッフル (つまり、Fisher-Yates、経由Collections.shuffle
) を適用し、行列にこれらの値を入力し始めます。
static <T> void fill(final T[][] matrix, final T... space) {
final int w = matrix.length;
final int h = matrix[0].length;
final int area = w * h;
final List<T> sample = new ArrayList<T>(area);
final int half = area >> 1;
sample.addAll(Collections.nCopies(half, space[0]));
sample.addAll(Collections.nCopies(half, space[1]));
Collections.shuffle(sample);
final Iterator<T> cursor = sample.iterator();
for (int x = w - 1; x >= 0; --x) {
final T[] column = matrix[x];
for (int y = h - 1; y >= 0; --y) {
column[y] = cursor.next();
}
}
}