データベースから一般的なリスト コレクション (List) を返すメソッドがあります。このコレクションには、注文の詳細、つまり、注文 ID、注文名、製品の詳細などがあります。
また、このメソッドは、注文日の降順でソートされた上位 5 つの注文のみを含むコレクションを返します。
私の要件は、クライアントがこのメソッドを呼び出すたびに、5 つのランダムな順序を持つコレクションを返す必要があるということです。
C# を使用してこれを達成するにはどうすればよいですか?
データベースから一般的なリスト コレクション (List) を返すメソッドがあります。このコレクションには、注文の詳細、つまり、注文 ID、注文名、製品の詳細などがあります。
また、このメソッドは、注文日の降順でソートされた上位 5 つの注文のみを含むコレクションを返します。
私の要件は、クライアントがこのメソッドを呼び出すたびに、5 つのランダムな順序を持つコレクションを返す必要があるということです。
C# を使用してこれを達成するにはどうすればよいですか?
しばらく前に、 Fisher-Yates shuffleを使用してこれを行う TakeRandom 拡張メソッドを作成しました。実際に返品したいアイテムの数をランダム化するだけで済み、偏りがないことが保証されているため、非常に効率的です。
public static IEnumerable<T> TakeRandom<T>(this IEnumerable<T> source, int count)
{
var array = source.ToArray();
return ShuffleInternal(array, Math.Min(count, array.Length)).Take(count);
}
private static IEnumerable<T> ShuffleInternal<T>(T[] array, int count)
{
for (var n = 0; n < count; n++)
{
var k = ThreadSafeRandom.Next(n, array.Length);
var temp = array[n];
array[n] = array[k];
array[k] = temp;
}
return array;
}
ThreadSafeRandom の実装は、PFX チームのブログ にあります。
あなたは本当にデータベースでこれを行うべきです - 床に5つを除いてすべてを落とすためだけに大きなスタックを返すことは意味がありません. 人々がより良い答えを出せるように、どのタイプのデータアクセススタックが関係しているかを説明するように質問を修正する必要があります。たとえば、ORDER BY RAND() を実行できます。
SELECT TOP 5 ... FROM orders
ORDER BY RAND()
しかし、それはあなたが望まないすべての行を訪問します。SQL Server を使用している場合 [それに結び付けたい:P]、TABLESAMPLEを使用できます。
編集:残りの部分はここにないふりをしてください-効率的ではないため、クライアント側で並べ替えたい場合は、グレッグの答えがはるかに望ましいです。
ただし、完全を期すために、次をLINQPadに貼り付けます。
var orders = new[] { "a", "b", "c", "d", "e", "f" };
var random = new Random();
var result = Enumerable.Range(1,5).Select(i=>orders[random.Next(5)])
result.Dump();
編集:グレッグのポイントに対する力ずくの答え(はい、効率的でもきれいでもありません)
var orders = new[] { "a", "b", "c", "d", "e", "f" };
var random = new Random();
int countToTake = 5;
var taken = new List<int>( countToTake);
var result = Enumerable.Range(1,countToTake)
.Select(i=>{
int itemToTake;
do {
itemToTake = random.Next(orders.Length);
} while (taken.Contains(itemToTake));
taken.Add(itemToTake);
return orders[itemToTake];
});
result.Dump();
return myList.OfType<Order>().OrderBy(o => Guid.NewGuid()).Take(5);
return collection.Where(()=>Random.Next(100) > (5 / collection.Count * 100)));