我有一个从数据库返回通用列表集合(List)的方法。此系列包含订单详细信息,即订单ID,订单名称,产品详细信息等。
此外,该方法返回的集合只包含按订单日期降序排序的前5个订单。
我的要求是每次客户端调用此方法时,我都需要返回有5个随机命令的集合。
如何使用C#实现此目的?
答案 0 :(得分:12)
我在前一段时间写了一个TakeRandom扩展方法,使用Fisher-Yates shuffle来做到这一点。这是非常有效的,因为它只会让您实际想要返回的项目数量随机化,并保证不偏不倚。
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。
答案 1 :(得分:4)
你真的应该在数据库中做到这一点 - 没有必要返回大量的东西,只丢掉五个人。您应该修改您的问题以解释涉及哪种类型的数据访问堆栈,以便人们可以提供更好的答案。例如,你可以做一个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();
编辑:蛮力回答格雷格的观点(是的,效率不高或漂亮)
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();
答案 2 :(得分:2)
return myList.OfType<Order>().OrderBy(o => Guid.NewGuid()).Take(5);
答案 3 :(得分:1)
return collection.Where(()=>Random.Next(100) > (5 / collection.Count * 100)));