1. ホーム
  2. java

[解決済み】重複のない乱数の作成

2022-02-17 09:05:17

質問

この場合、MAXが5しかないので、1つずつ重複をチェックすればいいのですが、もっと簡単な方法はないでしょうか?例えば、MAXが20の場合はどうでしょうか? ありがとうございます。

int MAX = 5;

for (i = 1 , i <= MAX; i++)
{
        drawNum[1] = (int)(Math.random()*MAX)+1;

        while (drawNum[2] == drawNum[1])
        {
             drawNum[2] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) )
        {
             drawNum[3] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) )
        {
             drawNum[4] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[5] == drawNum[1]) ||
               (drawNum[5] == drawNum[2]) ||
               (drawNum[5] == drawNum[3]) ||
               (drawNum[5] == drawNum[4]) )
        {
             drawNum[5] = (int)(Math.random()*MAX)+1;
        }

}

解決方法は?

最も単純な方法は、可能性のある数字のリスト(1〜20など)を作成し、それを Collections.shuffle . そして、必要な数の要素を取ればいいのです。これは、範囲が最終的に必要な要素の数と同じであれば、素晴らしいことです(例:カードのデッキをシャッフルする場合)。

例えば、1.10,000の範囲から10個のランダムな要素が欲しい場合、それはあまりうまくいきません - あなたは不必要に多くの作業を行うことになります。その場合は、これまでに生成した値のセットを保持しておき、次の値が存在しなくなるまでループで数値を生成し続ける方がよいでしょう。

if (max < numbersNeeded)
{
    throw new IllegalArgumentException("Can't ask for more numbers than are available");
}
Random rng = new Random(); // Ideally just create one instance globally
// Note: use LinkedHashSet to maintain insertion order
Set<Integer> generated = new LinkedHashSet<Integer>();
while (generated.size() < numbersNeeded)
{
    Integer next = rng.nextInt(max) + 1;
    // As we're adding to a set, this will automatically do a containment check
    generated.add(next);
}

しかし、セットの選択には注意が必要です。私は非常に意図的に LinkedHashSet これは、挿入順序を維持するためで、ここではそれが重要なのです。

さらに別の選択肢として 常に その都度、範囲を狭め、既存の値を補正することで、前進します。例えば、0〜9の範囲で3つの値が必要だとします。最初の反復処理では、範囲0〜9の任意の数値を生成し、仮に4を生成したとする。

2回目の反復処理では、0〜8の範囲の数字を生成します。生成された数値が4より小さければそのままにし、そうでなければ1を足す。この方法で7を得たとしよう。

3回目の繰り返しで、0〜7の範囲の数字を生成します。生成された数字が4より小さければ、そのままにする。4または5なら、1つ足す。6または7なら、2つ足す。こうすると、結果の範囲は4や6を除いた0〜9になる。