LINQ:按随机顺序排序

63

我该如何修改以下代码,以便每次从数据库中获取50个不同的随机数据?

return (from examQ in idb.Exam_Question_Int_Tbl
      where examQ.Exam_Tbl_ID==exam_id
      select examQ).OrderBy(x=>x.Exam_Tbl_ID).Take(50);
3个回答

126

10
在时间t:A>B是正确的,因为您使用了x => Guid.NewGuid()。在时间t+n:A<B是正确的,因为您仍然使用了相同的方法。排序函数不是用来打乱顺序的,这可能会导致最坏情况下出现无限循环。 - L.B
1
进一步说,.Select( x => new { Guid = Guid.NewGuid, Question = x } ).OrderBy( x => x.Guid ).Select( x => x.Question ).Take(50); 可以用于内存选择,但是你必须排序,最佳算法平均为O(nlogn)。Durstenfeldt算法通过取集合并将每个元素依次与尚未迭代的集合中的随机元素交换来工作。这提供了随机的排序,但只需要O(n)个操作。 - tvanfosson
3
请记住,对于具有大量行的表,使用 ORDER BY NEWID() 将非常慢。如果您考虑它的工作原理,它会为每一行生成一个随机数,然后对它们进行排序。对整个表进行排序是慢的。如果是这种情况,请使用另一种策略,例如:http://msdn.microsoft.com/en-us/library/cc441928.aspx(请记住不要使用 TOP,而是先在结果中使用 ORDER BY NEWID()),或者使用在 SQL Server >=2005 中可用的 TABLESAMPLE 子句。该子句使其返回数据的随机页,因此仅触摸了部分数据。非常快速。 - NothingsImpossible
请注意,只有在使用.Take(n)n>elements.Count时才能正常工作。 - Bellash
1
@Bellash:在LINQ-To-SQL中,顺序似乎被删除了,请查看这个针对您的答案:https://dev59.com/MnRB5IYBdhLWcg3wXWK2#648247。上述代码适用于Linq-To-Entities或Linq-To-Objects(因此,在`Where`之后需要一个`ToList`,这可能会很慢)。 - Tim Schmelter
显示剩余7条评论

10

集合有多大?您能将它们全部选择到内存中,然后选择一个随机集合吗?如果可以的话,那么Is using Random and OrderBy a good shuffle algorithm?中的Shuffle算法是一个不错的选择。

return idb.Exam_Question_Int_Tbl
          .Where( e => e.Exam_Tbl_ID == exam_id )
          .ToList()
          .Shuffle()
          .Take( 50 );

如果不行的话,我建议使用一个存储过程,根据 newid() 进行排序(SQL Server 随机排序)。我认为在 C# 中基于随机数生成器的表达式无法转换成 LINQ to SQL/Entities。


5

如果你遇到了和我一样的问题...

int Limit = 24;
return (from Q in Context.table
where Q.some_key == 1234
select new classDataType() { 
    FirstAttribute = Q.FirstCol,
    SecondAttribute = Q.SecondCol,
    ThirdAttribute = Q.ThirdCol
}).ToList().OrderBy(x => Guid.NewGuid()).Take(Limit).ToList();

在使用OrderBy-NewGuid-Method之前,由于sql-linq需要它是一个列表,因此您可能需要将其更改为列表。

return (...-SQL-SELECT-LINQ-...)
    .ToList() //****
    .OrderBy(x => Guid.NewGuid()).Take(Limit).ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接