我有一個方法從數據庫中返回一個通用列表集合(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的實現可以是found at the PFX team blog。
return collection.Where(()=>Random.Next(100) > (5/collection.Count * 100)));
與礦,你可以得到dups(也許不會得到五個) – 2009-12-08 12:17:54
return myList.OfType<Order>().OrderBy(o => Guid.NewGuid()).Take(5);
這'訪問'陣列的每個項目(是的,我知道你知道) – 2009-12-08 12:09:20
是的。我不明白原始問題中* generics *要求的作用。如果我們只是有一個訂單列表,我們可以放棄'OfType',而上面的查詢對於linq到sql表格的列表也同樣適用。如果它是一個sql表的linq,那麼'OrderBy'子句實際上會在數據庫級別解析爲'newid()'隨機化的順序,這是完全可取的(正如你指出的那樣) – 2009-12-08 12:23:37
@David:我認爲asker意味着列表
你真的應該在數據庫中做到這一點 - 沒有意義只返回一大堆東西,只能放下所有五個。你應該修改你的問題來解釋什麼類型的數據訪問棧被涉及,這樣人們可以給出更好的答案。例如,你可以做一個ORDER BY RAND():
SELECT TOP 5 ... FROM orders
ORDER BY RAND()
但是那visits every row, which you don't want。如果您正在使用SQL Server [並且希望與其綁定:P],則可以使用TABLESAMPLE。
If you're using LINQ to SQL, go here
編輯:這裏只是假裝這個心不是的剩下的 - 它的效率不高,因此Greg的答覆是更爲可取的,如果你想客戶端進行排序。
但是,對於完整性,以下內容粘貼到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();
編輯:蠻力回答Greg的點(是的,效率不高,或者漂亮)
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();
雖然這將返回重複,這可能不是他所追求的。 – 2009-12-08 12:13:16
@Greg Beech:好點,會解決(真正的問題是他的排序需要在數據庫中發生) – 2009-12-08 12:15:04
投票。絕對應該在數據庫上做到這一點。 – Firestrand 2009-12-08 13:40:41
+1:這是一個相當完整的答案:D – 2009-12-08 12:17:22
雖然它似乎在複製列表(效率?)或修改現有的(從簽名中不太明顯)。 – 2009-12-08 12:20:02
@Vilk:正如我的廢話答案所證明的那樣,要避免有效地重複是很不容易的,所以我懷疑它很難提高效率。 – 2009-12-08 12:38:14