重ならない乱数配列の作成

2023年2月22日

トランプのシャッフルなど、シャッフルをするのですが重なってはいけないケースの場合を考えてみましょう

C#の基本文法だけでも作成できますが、今回は一足飛びにLINQを使った方法を紹介します

0から9までの10個の整数をシャッフルするコード

元になるコード

int[] randomNumbers = Enumerable.Range(0, 10).OrderBy(_ => Guid.NewGuid()).ToArray();

0から9までの数字をランダムに並び替えた整数型の配列を作成します。

まず、Enumerable.Range(0, 10)は、0から9までの整数のシーケンスを作成します。

OrderBy(_ => Guid.NewGuid())は、ランダムなGUID(グローバル一意識別子)を使用して、配列の要素をランダムに並び替えます。

最後に、ToArray()メソッドを使用して、並び替えられたシーケンスを整数型の配列に変換します。

テスト用コード

int[] randomNumbers = Enumerable.Range(0, 10).OrderBy(_ => Guid.NewGuid()).ToArray();

foreach (var number in randomNumbers)
{
    Console.WriteLine(number);
}

結果

0
8
1
2
7
3
9
5
4
6

正数配列を渡して、シャッフルした結果を得るコード

元になるコード

int[] randomNumbers = numbers.OrderBy(_ => Guid.NewGuid()).ToArray();

このコードは、配列numbers内の要素をランダムな順序で並び替えるために使用されます。

OrderByメソッドは、LINQ(Language Integrated Query)によって提供される拡張メソッドの一種であり、IEnumerable<T>型のオブジェクトに対して使用されます。このメソッドは、指定されたキーに基づいてシーケンスの要素を昇順に並べ替えます。この例では、キーとしてランダムなGuidオブジェクトを使用しています。

Guid.NewGuid()は、ランダムなGUID(Globally Unique Identifier)を生成するための.NET Frameworkのメソッドです。

最後に、ToArray()メソッドは、結果を新しい配列として返します。randomNumbers変数は、ランダムに並び替えられたnumbersの要素が格納された新しい配列を表します。

テスト用コード

int[] numbers = new int[] { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };

int[] randomNumbers = numbers.OrderBy(_ => Guid.NewGuid()).ToArray();

foreach (var number in randomNumbers)
{
    Console.WriteLine(number);
}

結果

11
10
18
13
17
15
14
12
16
19

メソッドにしたテスト用コード

int[] numbers = new int[] { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };

int[] randomNumbers = ShuffleRange(numbers);

foreach (var number in randomNumbers)
{
    Console.WriteLine(number);
}

/// <summary>
/// 与えれたた正数配列をシャッフルします
/// </summary>
/// <param name="array">シャッフルする正数配列</param>
/// <returns>シャッフルされた正数配列</returns>
int[] ShuffleRange(int[] array) => array.OrderBy(_ => Guid.NewGuid()).ToArray();

結果

15
16
18
19
13
10
17
11
14
12

トランプのカードをシャッフルするサンプル

トランプのカードクラス

class Card
{
    public enum SuitEnum
    {
        Spade,
        Heart,
        Diamond,
        Club,
    }

    public Card(SuitEnum suit, int number)
    {
        Suit = suit;
        Number = number;
    }

    public SuitEnum Suit { get; set; }
    public int Number { get; set; }
}

カードのインスタンスを作成する

4つのマークで1-13までのカードを作成することとします

Card[] cards = new Card[52];

int counter = 0;

for (int number = 1; number <= 13; number++)
{
    for (int suit = 0; suit < 4; suit++)
    {
        Card.SuitEnum suitEnum = (Card.SuitEnum)suit;
        cards[counter++] = new Card(suitEnum, number);
    }
}

カードのインスタンス配列をシャッフルするジェネリックメソッド

    /// <summary>
    /// 与えれたたインスタンス配列をシャッフルします
    /// </summary>
    /// <param name="array">シャッフルする正数配列</param>
    /// <returns>シャッフルされたインスタンス配列</returns>
    T[] ShuffleRange<T>(T[] array) => array.OrderBy(_ => Guid.NewGuid()).ToArray();

インスタンスを作成したカードのインスタンス(山札)をシャッフルするためのメソッド呼び出し

Card[] shuffleCards = ShuffleRange(cards);

テスト用コード

foreach (var card in shuffleCards)
{
    Console.WriteLine($"{card.Suit} {card.Number}");
}

結果

Club 5
Club 6
Spade 7
Heart 4
Diamond 3
Heart 8
Spade 11
Club 11
Diamond 9
Heart 6
Diamond 5
Diamond 1
Diamond 8
Club 3
Diamond 4
Spade 12
Spade 4
Heart 2
Club 9
Heart 3
Club 13
Club 8
Diamond 6
Diamond 2
Spade 13
Club 10
Spade 10
Spade 9
Heart 10
Heart 7
Heart 5
Heart 1
Club 2
Spade 5
Heart 11
Diamond 12
Heart 12
Heart 13
Club 1
Club 12
Diamond 10
Spade 8
Spade 2
Diamond 7
Club 4
Heart 9
Diamond 13
Club 7
Diamond 11
Spade 3
Spade 1
Spade 6

トランプのシャッフルコード(Listバージョン)

List<Card> cards = new List<Card>();


int counter = 0;

for (int number = 1; number <= 13; number++)
{
    for (int suit = 0; suit < 4; suit++)
    {
        Card.SuitEnum suitEnum = (Card.SuitEnum)Enum.ToObject(typeof(Card.SuitEnum), suit);
        cards.Add(new Card(suitEnum, number));
    }
}

List<Card> shuffleCars = ShuffleRange(cards);
/// <summary>
/// 与えれたたインスタンス配列をシャッフルします
/// </summary>
/// <param name="array">シャッフルする正数配列</param>
/// <returns>シャッフルされたインスタンス配列</returns>
List<T> ShuffleRange<T>(List<T> array) => array.OrderBy(_ => Guid.NewGuid()).ToList();

foreach (var card in shuffleCars)
{
    Console.WriteLine($"{card.Suit} {card.Number}");
}

class Card
{
    public enum SuitEnum
    {
        Spade,
        Heart,
        Diamond,
        Club,
    }

    public Card(SuitEnum suit, int number)
    {
        Suit = suit;
        Number = number;
    }

    public SuitEnum Suit { get; set; }
    public int Number { get; set; }
}

C#

Posted by hidepon