C# 从集合中随机返回项目
我有一个从数据库返回通用列表集合(list)的方法。此集合具有订单详细信息,即订单Id、订单名称、产品详细信息等 此外,该方法还返回一个集合,该集合仅包含按订单日期降序排序的前5个订单 我的要求是,每次客户端调用此方法时,我都需要返回具有5个随机订单的集合 如何使用C#?C# 从集合中随机返回项目,c#,generics,random,filtering,random-sample,C#,Generics,Random,Filtering,Random Sample,我有一个从数据库返回通用列表集合(list)的方法。此集合具有订单详细信息,即订单Id、订单名称、产品详细信息等 此外,该方法还返回一个集合,该集合仅包含按订单日期降序排序的前5个订单 我的要求是,每次客户端调用此方法时,我都需要返回具有5个随机订单的集合 如何使用C#?返回myList.OfType().OrderBy(o=>Guid.NewGuid()).Take(5); 不久前,我编写了一个TakeRandom扩展方法,它使用。它非常有效,因为它只需将您实际想要返回的项目的数量随机化,并且
返回myList.OfType().OrderBy(o=>Guid.NewGuid()).Take(5);
不久前,我编写了一个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;
}
公共静态IEnumerable TakeRandom(此IEnumerable源,int计数)
{
var数组=source.ToArray();
返回ShuffleInternal(array,Math.Min(count,array.Length)).Take(count);
}
私有静态IEnumerable ShuffleInternal(T[]数组,int计数)
{
对于(变量n=0;n
ThreadSafeRandom的一个实现可以是。你真的应该在数据库中这样做——没有必要返回一大堆东西,结果除了五个以外,其余都掉在地上。您应该修改您的问题,以解释所涉及的数据访问堆栈的类型,以便人们能够给出更好的答案。例如,您可以按RAND()进行订购: 但是那。如果您使用的是SQL Server[并且希望与之绑定:P],则可以使用 编辑:假设其余部分不在这里-这不是有效的,因此,如果您确实想对客户端进行排序,Greg的答案更可取 但是,为了完整起见,请将以下内容粘贴到: 编辑:蛮力回答格雷格的观点(是的,不高效或不漂亮)
var orders=new[]{“a”、“b”、“c”、“d”、“e”、“f”};
var random=新的random();
int countToTake=5;
var TAKED=新列表(倒计时);
var结果=可枚举范围(1,countToTake)
.选择(i=>{
int ITEM TOTAKE;
做{
itemToTake=random.Next(orders.Length);
}while(take.Contains(itemToTake));
添加(itemToTake);
退货订单[待售物品];
});
result.Dump();
此“访问”阵列的每个项目(是的,我知道您知道)是的。我不明白泛型要求在最初的问题中起到了什么作用。如果我们有一个订单列表,我们可以删除类型的,上面的查询对于列表和linq to sql表同样有效。如果它是一个linq to sql表,OrderBy
子句实际上会在数据库级别解析为order by newid()
随机化,这是完全可取的(正如您所指出的)@David:我认为asker的意思是列表的类型与此无关。问题是NewGuid的效率不如Random()(记住,每个Guid都是神圣的,每个Guid都是伟大的。还没有意识到默认的L2S[大概还有EF和LLBLGP等]默认的按翻译排序-这使得这个世界变成了a+1。(你应该在帖子中说,你应该:D)我猜=)我被通用列表中的五个订单弄糊涂了。这是对guid的公然浪费,虽然,我不想让它们变得不那么唯一,但会返回重复的,这可能不是他想要的。@Greg Beech:好的,will fix(真正的问题是他的排序需要在数据库中进行)和我的一样,你可以得到重复(可能不会得到五个)虽然它似乎在复制列表(效率?)或修改现有列表(从签名上看不明显)。@Vilk:正如我糟糕的回答所证明的,要有效避免重复是不容易的,所以我怀疑很难打败它efficiency@Vilk-是的,你说得对,它确实修改了原始列表。我把它改了,所以现在不会了。不幸的是,它必须将集合复制到一个数组中,但这是很难避免的(尽管我确信有一种方法…)@Ryan:这会有什么区别?它返回的是随机项,所以数组是向前还是向后遍历都没有区别。@Ryan-可以编写Durstenfeld实现来反转任意方向的列表。虽然反向实现更常见,但正向实现在这里更好,因为它意味着它只需要洗牌前n个元素,而不是全部元素,因为它不需要洗牌不会返回的元素。
return myList.OfType<Order>().OrderBy(o => Guid.NewGuid()).Take(5);
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;
}
SELECT TOP 5 ... FROM orders
ORDER BY RAND()
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();