Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从集合中随机返回项目_C#_Generics_Random_Filtering_Random Sample - Fatal编程技术网

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扩展方法,它使用。它非常有效,因为它只需将您实际想要返回的项目的数量随机化,并且

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

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

我的要求是,每次客户端调用此方法时,我都需要返回具有5个随机订单的集合

如何使用C#?

返回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();