【アルゴリズム】C# 配列要素を漏れ・ダブりなくランダムに取得する方法

この記事では、配列の要素をランダムに漏れ・ダブりなく取得するアルゴリズムについて説明します。

1. この記事で実現すること

たとえば、以下のような配列があったとします。

[1, 5, 8, 13, 35, 67]

この各要素をランダムに漏れ・ダブりなく抽出する方法を考えてみます。

  • 正しい結果

    • [ 35, 8, 13, 67, 5, 1]
    • [ 67, 1, 5, 35, 12, 5]
  • 間違った結果

    • 13 が重複している
    • [ 8, 1, 5, 13, 13, 35, 67]
    • 67が漏れている
    • [ 8, 1, 5, 13, 35]

2. アルゴリズムの概要

1. 0から配列の要素数 – 1 までの整数の乱数を取得します。

以下の場合、要素数は6個です。

[1, 5, 8, 13, 35, 67] 0~5の整数をランダムで選びます。ランダムで「3」が選ばれたとします。

2. ランダム数字に該当する配列の要素を取得します。

以下の場合、3番目の要素は「13」です(配列の1つ目の添え字を0とした場合)

[1, 5, 8, 13, 35, 67]

3. 抽出した配列の要素を、配列から削除します。

今回は「13」が選ばれましたので、「13」を配列から削除します。

削除前は以下のとおりです。

[1, 5, 8, 13, 35, 67]

削除後は、以下のようになります。

[1, 5, 8, 35, 67]

4. 「1.」に戻ります。0から配列の要素数-1までの整数の乱数を取得します。

先ほど、要素「13」が消えましたので、要素数は「5」です。

[1, 5, 8, 35, 67]

ランダムで「0」が選ばれたとします。

5. 「2.」の手順を行います。ランダム数字に該当する配列の要素を取得します。

以下の配列のうち、手順「4.」で取得した乱数0に対応する要素は「1」になります。

[1, 5, 8, 35, 67]

6. 「3.」の手順を行います。抽出した配列の要素を、配列から削除します。

今回は「1」が選ばれましたので、「1」を配列から削除します。

削除前は以下のとおりです。

[1, 5, 8, 35, 67]

削除後は、以下のようになります。

[5, 8, 35, 67]

7. 手順「4.」「5.」「6.」を繰り返します。配列の要素がなくなったら終了です。

3. c#で書くとどうなるか?

c#で書くと、こうなります。


    int[] ArrayItems = { 1, 5, 8, 13, 35, 67 };
    Random rand = new Random();
    int choiceIdx = 0;

    while(ArrayItems.Length > 0)
    {
        choiceIdx = rand.Next(0, ArrayItems.Length);

        Console.WriteLine($Output: {ArrayItems[choiceIdx]});

        List<int> ArrayItemsList = new List<int>();
        ArrayItemsList.AddRange(ArrayItems);
        ArrayItemsList.Remove(ArrayItems[choiceIdx]);
        ArrayItems = ArrayItemsList.ToArray();
    }

まず、抽出したい配列を定義します。

    int[] ArrayItems = { 1, 5, 8, 13, 35, 67 };

次にRandomオブジェクトを生成します。

    Random rand = new Random();

ランダム抽出対象の添え字ワークエリアを初期化します。

    int choiceIdx = 0;

抽出対象の配列の要素数が「0より大きい」を満たすまでループします。

    while(ArrayItems.Length > 0)
    {

        ...

    }

ランダム抽出対象の添え字を取得し、配列から要素を取得します。

    choiceIdx = rand.Next(0, ArrayItems.Length);
    Console.WriteLine($Output: {ArrayItems[choiceIdx]});

配列から要素を削除します。 配列から要素を直接削除する方法がわかりませんでしたので、一旦リストオブジェクトに変換し、リストから要素を削除して、配列に戻しています。

        List<int> ArrayItemsList = new List<int>();
        ArrayItemsList.AddRange(ArrayItems);
        ArrayItemsList.Remove(ArrayItems[choiceIdx]);
        ArrayItems = ArrayItemsList.ToArray();

以下のように出力されれば、成功です。

Output: 35
Output: 67
Output: 13
Output: 8
Output: 1
Output: 5

以上、アルゴリズムでした。

おすすめ本 c#コードレシピ集

c#コードレシピ集は、「文字列を大文字あるいは小文字に変換したい」や「Taskをキャンセルしたい」など逆引き的にコードの書き方を調べられるレシピ集です。

2021年8月に発売された本で、全部で385個のレシピが収録されています。

ジャンルは日付処理やLINQ、並列処理と非同期処理など幅広く記載されています。

Kindle対応ですので、まずはサンプルをダウンロードして何が書かれているか確認してはいかがでしょうか。

コメント

タイトルとURLをコピーしました