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

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

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

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

元になるコード

int[] randomNumbers = Enumerable.Range(0, 10).OrderBy(_ => Guid.NewGuid()).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();

テスト用コード

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)Enum.ToObject(typeof(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[] shuffleCars = ShuffleRange(cards);

テスト用コード

foreach (var card in shuffleCars)
{
    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