.NET 8で追加されたRandom.Shuffle
メソッドとRandom.GetItems
メソッドの中身を確認しておく。(.NET 8.0 リリース時点)
前者はシャッフル、後者は選択肢の中からランダムに選ぶ(よその名前では choice とか sample とか)もの。
なお、System.Security.Cryptography.RandomNumberGenerator
にも同様のメソッドが追加されている。
Shuffle
メソッド
待望(?)の標準ライブラリシャッフル。
・Random.Shuffle メソッド (System) | Microsoft Learn
Span<int> span = [1, 2, 3, 4, 5]; Random.Shared.Shuffle(span); // List のオーバーロードはない List<int> list = [1, 2, 3, 4, 5]; Random.Shared.Shuffle(CollectionsMarshal.AsSpan(list));
中身はフィッシャー・イェーツアルゴリズム。外部領域は利用しない。
・Source Browser(リンク先:Shuffle(Span<T>)
)
新しく書くなら使わない理由はないはず。
OrderBy(_ => Guid.NewGuid())
は姿を消すだろうか。消さないかな。
GetItems
メソッド
待望(?)の標準ライブラリチョイス。
・Random.GetItems メソッド (System) | Microsoft Learn
destination を渡すものと length を渡すものがあるが、後者は中で配列をnew
して destination としている。
ReadOnlySpan<int> choices = [1, 2, 3, 4, 5]; Span<int> zyuuren = stackalloc int[10]; Random.Shared.GetItems(choices, zyuuren); int[] zyuurenArray = Random.Shared.GetItems(choices, 10);
中身は現在のところ、選択肢のReadOnlySpan<T>
(choices) から destination に対し、ループしてchoices[Next(choices.Length)]
を詰めていくだけ。
・runtime/src/libraries/System.Private.CoreLib/src/System/Random.cs at 51cce4207b8484cac28aa1932ce797e9ea2ad929 · dotnet/runtime · GitHub
「現在のところ」というのは、特定条件での高速化がマージされているため。
・Optimize Random{NumberGenerator}.GetItems for power-of-two choices by stephentoub · Pull Request #92229 · dotnet/runtime · GitHub
・Source Browser(リンク先:GetItems(ReadOnlySpan<T>, Span<T>)
)
choices のLength
が2の累乗かつ256以下のとき、ループして都度Next
するのではなくNextBytes
から一気にチョイスするという感じ。
選択肢の数の話なので都合の良い数に設定できるかは場合によるけれど、上記条件のとおりにしておければ将来勝手に速くなる恩恵を受けることができる。