从集合中随机返回项目

我有一个从数据库返回通用列表集合(List)的方法。 此系列包含订单详细信息,即订单ID,订单名称,产品详细信息等。

此外,该方法返回一个集合,该集合仅包含按订单日期降序排序的前5个订单。

我的要求是每次客户端调用此方法时,我需要返回有5个随机命令的集合。

我如何使用C#实现这一目标?

我一段时间后写了一个TakeRandom扩展方法,使用Fisher-Yates shuffle来做这件事。 这是非常有效的,因为它只是麻烦随机化你真正想要返回的项目数量,并保证是无偏见的。

public static IEnumerable TakeRandom(this IEnumerable source, int count) { var array = source.ToArray(); return ShuffleInternal(array, Math.Min(count, array.Length)).Take(count); } private static IEnumerable ShuffleInternal(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; } 

可以在PFX团队博客中找到 ThreadSafeRandom的实现。

你真的应该在数据库中做到这一点 – 没有必要返回一大堆东西,只丢掉五个人。 您应该修改您的问题以解释涉及哪种类型的数据访问堆栈,以便人们可以提供更好的答案。 例如,你可以做一个ORDER BY RAND():

 SELECT TOP 5 ... FROM orders ORDER BY RAND() 

但那会访问你不想要的每一行 。 如果您正在使用SQL Server [并希望与它绑定:P],您可以使用TABLESAMPLE 。

如果您正在使用LINQ to SQL,请转到此处

编辑:只是假装其余部分不在这里 – 它效率不高,因此如果你想对客户端进行排序,那么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( 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().OrderBy(o => Guid.NewGuid()).Take(5); 
 return collection.Where(()=>Random.Next(100) > (5 / collection.Count * 100)));