我有一个方法从数据库中返回一个通用列表集合(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