【问题标题】:linq: order by randomlinq:随机排序
【发布时间】: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);

【问题讨论】:

    标签: c# linq random


    【解决方案1】:

    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

    【讨论】:

    • 我认为这无论如何都不适用于数据库(没有转换为 SQL),它最终最多是 O(nlogn)。无论如何,您的比较器需要提供总排序(它不需要)。您可以通过为每个元素选择一个新的 GUID(一次),然后按此排序来修复它,但如果您正在进行内存随机选择,Fisher-Yates Shuffle(Durstenfeldt 的版本)是一个更好的选择。
    • -1 blogs.msdn.com/b/ericlippert/archive/2011/01/20/…。在时间 t:A>B 是真的,因为你的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 子句。该子句使它返回随机的数据页,因此只有一部分数据被触及。非常快。
    • @Bellash:在 LINQ-To-SQL 中,订单似乎已被删除,请查看适合您的答案:stackoverflow.com/a/648247/284240 以上代码适用于 Linq-To-Entities 或 Linq -To-Objects(因此您需要在 Where 之后添加 ToList,这可能会很慢)。
    【解决方案2】:

    收藏有多大?您可以将它们全部选择到内存中然后选择一个随机集合吗?如果是这样,那么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。

    【讨论】:

      【解决方案3】:

      如果你有同样的问题,我有...

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-04
        • 2012-11-19
        • 2012-01-05
        • 1970-01-01
        • 2010-10-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多