配列・コレクションをシャッフルする方法について。
配列・コレクション・IEnumerable<T>のシャッフル
Enumerable.OrderByメソッドを使って任意のIEnumerable<T>をシャッフルするためのメソッドの例。 OrderByメソッドに対してランダムなキーを与えることで、ランダムな順序に並べ替える。
この例では、ランダムなキーの生成にRandomNumberGeneratorクラスを使用しているが、Randomクラスを用いても同じように実装できる。 また、使いやすいように拡張メソッドとして呼び出せるようにしてある。
このメソッドはOrderByメソッドを用いているため、オリジナルのIEnumerable<T>には変更を加えない(非破壊的)。
任意のIEnumerable<T>をシャッフルする拡張メソッド
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
public static class IEnumerableExtensions {
public static IOrderedEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source)
{
return Shuffle(source, RandomNumberGenerator.Create());
}
public static IOrderedEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source, RandomNumberGenerator rng)
{
if (source == null)
throw new ArgumentNullException("source");
var bytes = new byte[4];
return source.OrderBy(delegate(TSource e) {
rng.GetBytes(bytes);
return BitConverter.ToInt32(bytes, 0);
});
/* Randomクラスを使う場合
var random = new Random();
return source.OrderBy(delegate(TSource e) {
return random.Next();
});
*/
}
}
class Sample {
static void Main()
{
var col1 = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Print(col1);
Print(col1.Shuffle());
var col2 = new Queue<string>(new[] {"foo", "bar", "baz"});
Print(col2);
Print(col2.Shuffle());
var col3 = new List<int>();
Print(col3);
Print(col3.Shuffle());
}
private static void Print<T>(IEnumerable<T> source)
{
foreach (var val in source) {
Console.Write(val);
Console.Write(" ");
}
Console.WriteLine();
}
}
任意のIEnumerable<T>をシャッフルする拡張メソッド
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Security.Cryptography
Module IEnumerableExtensions
<System.Runtime.CompilerServices.Extension()> _
Public Function Shuffle(Of TSource)(ByVal source As IEnumerable(Of TSource)) As IOrderedEnumerable(Of TSource)
Return Shuffle(source, RandomNumberGenerator.Create())
End Function
Public Function Shuffle(Of TSource)(ByVal source As IEnumerable(Of TSource), ByVal rng As RandomNumberGenerator) As IOrderedEnumerable(Of TSource)
If source Is Nothing Then Throw New ArgumentNullException("source")
Dim bytes(3) As Byte
Return source.OrderBy(Function(e)
rng.GetBytes(bytes)
Return BitConverter.ToInt32(bytes, 0)
End Function)
' Randomクラスを使う場合
'Dim random As New Random()
'
'Return source.OrderBy(Function(e)
' Return random.Next()
'End Function)
End Function
End Module
Class Sample
Shared Sub Main()
Dim arr1() As Integer = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Print(arr1)
Print(arr1.Shuffle())
Dim arr2 As New Queue(Of String)(New String() {"foo", "bar", "baz"})
Print(arr2)
Print(arr2.Shuffle())
Dim arr3 As New List(Of Integer)()
Print(arr3)
Print(arr3.Shuffle())
End Sub
Private Shared Sub Print(Of T)(ByVal source As IEnumerable(Of T))
For Each val As T In source
Console.Write(val)
Console.Write(" ")
Next
Console.WriteLine()
End Sub
End Class
実行結果の例
0 1 2 3 4 5 6 7 8 9 8 9 3 0 4 6 1 2 5 7 foo bar baz baz bar foo Press any key to continue
配列のシャッフル
配列のシャッフルを行うためのメソッドの例。 使いやすいように拡張メソッドとして呼び出せるようにしてある。 オリジナルの配列には変更を加えず(非破壊的)、シャッフルした配列を戻り値として返す。
配列をシャッフルする拡張メソッド
using System;
public static class ArrayExtensions {
public static T[] Shuffle<T>(this T[] array)
{
return Shuffle(array, new Random());
}
public static T[] Shuffle<T>(this T[] array, Random random)
{
if (array == null)
throw new ArgumentNullException("array");
if (random == null)
throw new ArgumentNullException("random");
var shuffled = (T[])array.Clone();
if (shuffled.Length < 2)
return shuffled;
for (var i = 1; i < shuffled.Length; i++) {
var j = random.Next(0, i + 1);
// swap
var temp = shuffled[i];
shuffled[i] = shuffled[j];
shuffled[j] = temp;
}
return shuffled;
}
}
class Sample {
static void Main()
{
var arr1 = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Print(arr1);
Print(arr1.Shuffle());
var arr2 = new string[] {"foo", "bar", "baz"};
Print(arr2);
Print(arr2.Shuffle());
var arr3 = new int[] {};
Print(arr3);
Print(arr3.Shuffle());
}
private static void Print<T>(T[] arr)
{
foreach (var val in arr) {
Console.Write(val);
Console.Write(" ");
}
Console.WriteLine();
}
}
配列をシャッフルする拡張メソッド
Imports System
Module ArrayExtensions
<System.Runtime.CompilerServices.Extension()> _
Public Function Shuffle(Of T)(ByVal array As T()) As T()
Return Shuffle(array, New Random())
End Function
Public Function Shuffle(Of T)(ByVal array As T(), ByVal random As Random) As T()
If array Is Nothing Then Throw New ArgumentNullException("array")
If random Is Nothing Then Throw New ArgumentNullException("random")
Dim shuffled As T() = DirectCast(array.Clone(), T())
If shuffled.Length < 2 Then Return shuffled
For i As Integer = 1 To shuffled.Length - 1
Dim j As Integer = random.Next(0, i + 1)
' swap
Dim temp As T = shuffled(i)
shuffled(i) = shuffled(j)
shuffled(j) = temp
Next
Return shuffled
End Function
End Module
Class Sample
Shared Sub Main()
Dim arr1 As Integer() = New Integer() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Print(arr1)
Print(arr1.Shuffle())
Dim arr2 As String() = New String() {"foo", "bar", "baz"}
Print(arr2)
Print(arr2.Shuffle())
Dim arr3 As Integer() = New Integer() {0}
Print(arr3)
Print(arr3.Shuffle())
End Sub
Private Shared Sub Print(Of T)(ByVal arr As T())
For Each val As T In arr
Console.Write(val)
Console.Write(" ")
Next
Console.WriteLine()
End Sub
End Class
実行結果の例
0 1 2 3 4 5 6 7 8 9 4 8 5 9 3 0 2 6 1 7 foo bar baz bar foo baz Press any key to continue