【发布时间】:2012-03-16 00:10:13
【问题描述】:
如何更改以下代码,每次从数据库中获取 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);
【问题讨论】:
如何更改以下代码,每次从数据库中获取 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);
【问题讨论】:
http://msdn.microsoft.com/en-us/library/system.guid.newguid.aspx
return (from examQ in idb.Exam_Question_Int_Tbl
where examQ.Exam_Tbl_ID==exam_id
select examQ).OrderBy(x => Guid.NewGuid()).Take(50);
如果这是 LINQ-to-SQL,您可以简单地将 ORDER BY NEWID() 添加到您的 SELECT 语句中。
正如评论所说,使用Fisher-Yates Shuffle 之类的算法可能会更好,这是一个实现:https://stackoverflow.com/a/375446/284240
【讨论】:
x => Guid.NewGuid()。在时间 t+n:Ax => Guid.NewGuid()。排序函数并非设计用于打乱事物,在最坏的情况下可能会导致无限循环。
.Select( x => new { Guid = Guid.NewGuid, Question = x } ).OrderBy( x => x.Guid ).Select( x => x.Question ).Take(50); 适用于内存选择,但您必须对其进行排序,平均 O(nlogn) 才能获得最佳算法。 Durstenfeldt 的算法通过获取一个集合并将每个元素依次与集合中尚未迭代的随机元素交换来工作。这提供了随机排序,但只需要 O(n) 次操作。
ORDER BY NEWID() 在有很多行的表上会非常慢。如果您考虑它的工作原理,它会为每一行生成一个随机数,然后对它们进行排序。对整个表进行排序是慢。如果是这种情况,请使用另一种策略,例如 msdn.microsoft.com/en-us/library/cc441928.aspx(请记住不要使用 TOP,首先在结果行上使用 ORDER BY NEWID()),或使用 SQL Server >=2005 中可用的 TABLESAMPLE 子句。该子句使它返回随机的数据页,因此只有一部分数据被触及。非常快。
Where 之后添加 ToList,这可能会很慢)。
收藏有多大?您可以将它们全部选择到内存中然后选择一个随机集合吗?如果是这样,那么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 Random Sort) 进行排序的存储过程。我认为没有任何方法可以将基于 C# 中的随机数生成器的表达式转换为 LINQ to SQL/Entities。
【讨论】:
如果你有同样的问题,我有...
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();
在 sql-linq 之后它需要是一个 LIST,所以在您使用 OrderBy-NewGuid-Method 之前,您可能需要更改为一个列表:
return (...-SQL-SELECT-LINQ-...)
.ToList() //****
.OrderBy(x => Guid.NewGuid()).Take(Limit).ToList();
【讨论】: