当我遇到条件时,使用Linq to SQL检索随机行的最佳(也是最快)方法是什么?某些领域必须是真的吗?
答案 0 :(得分:166)
您可以使用假UDF在数据库中执行此操作;在部分类中,向数据上下文添加方法:
partial class MyDataContext {
[Function(Name="NEWID", IsComposable=true)]
public Guid Random()
{ // to prove not used by our C# code...
throw new NotImplementedException();
}
}
然后只是order by ctx.Random()
;这将在SQL-Server NEWID()
提供随机排序。即。
var cust = (from row in ctx.Customers
where row.IsActive // your filter
orderby ctx.Random()
select row).FirstOrDefault();
请注意,这仅适用于中小型表格;对于巨大的表,它会对服务器产生性能影响,找到行数(Count
)会更有效,然后随机选择一行(Skip/First
)。
计数方法:
var qry = from row in ctx.Customers
where row.IsActive
select row;
int count = qry.Count(); // 1st round-trip
int index = new Random().Next(count);
Customer cust = qry.Skip(index).FirstOrDefault(); // 2nd round-trip
答案 1 :(得分:58)
实体框架的另一个示例:
var customers = db.Customers
.Where(c => c.IsActive)
.OrderBy(c => Guid.NewGuid())
.FirstOrDefault();
这不适用于LINQ to SQL。 OrderBy
只是被删除了。
答案 2 :(得分:29)
奇怪的是,你实际上并不需要计算。但是,除非得到计数,否则你需要获取每个元素。
您可以做的是保持“当前”值和当前计数的概念。当你获取下一个值时,取一个随机数并用“new”替换“current”,概率为1 / n,其中n是计数。
因此,当您读取第一个值时,总是使其成为“当前”值。当您读取第二个值时,可能使其成为当前值(概率1/2)。当您读取第三个值时,可能使其成为当前值(概率1/3)等。当您的数据用尽时,当前值是所有值中的随机值你读的是统一的概率。
要将条件应用于条件,请忽略任何不符合条件的条件。最简单的方法是首先考虑“匹配”序列,首先应用Where子句。
这是一个快速实施。我认为没关系......
public static T RandomElement<T>(this IEnumerable<T> source,
Random rng)
{
T current = default(T);
int count = 0;
foreach (T element in source)
{
count++;
if (rng.Next(count) == 0)
{
current = element;
}
}
if (count == 0)
{
throw new InvalidOperationException("Sequence was empty");
}
return current;
}
答案 3 :(得分:18)
实现高效实现的一种方法是在数据Shuffle
中添加一列,该列填充了随机int(创建每条记录时)。
以随机顺序访问表的部分查询是......
Random random = new Random();
int seed = random.Next();
result = result.OrderBy(s => (~(s.Shuffle & seed)) & (s.Shuffle | seed)); // ^ seed);
这在数据库中执行XOR操作,并按XOR的结果进行排序。
优点: -
这是我的家庭自动化系统用于随机化播放列表的方法。它每天都会选择一个新的种子,在白天提供一致的顺序(允许轻松的暂停/恢复功能),但每个新的一天都会重新查看每个播放列表。
答案 4 :(得分:7)
如果你想得到例如来自表的var count = 16
个随机行,你可以写
var rows = Table.OrderBy(t => Guid.NewGuid())
.Take(count);
这里我使用了E.F,而表格是Dbset
答案 5 :(得分:1)
如果获取随机行的目的是抽样,我已经非常简短地谈到了{Larson等人,Microsoft研究团队的一个很好的方法,他们使用物化视图为Sql Server开发了一个抽样框架。还有实际论文的链接。
答案 6 :(得分:1)
List<string> lst = new List<string>();
lst.Add("Apple");
lst.Add("Guva");
lst.Add("Graps");
lst.Add("PineApple");
lst.Add("Orange");
lst.Add("Mango");
var customers = lst.OrderBy(c => Guid.NewGuid()).FirstOrDefault();
说明:通过插入guid(随机),orderby的顺序是随机的。
答案 7 :(得分:0)
我对DataTable
s进行随机函数查询:
var result = (from result in dt.AsEnumerable()
order by Guid.NewGuid()
select result).Take(3);
答案 8 :(得分:0)
来到这里想知道如何从少数几个中获取一些随机页面,因此每个用户获得一些不同的随机3页。
这是我的最终解决方案,使用LINQ对Sharepoint 2010中的页面列表进行查询。它在Visual Basic中,抱歉:p
Dim Aleatorio As New Random()
Dim Paginas = From a As SPListItem In Sitio.RootWeb.Lists("Páginas") Order By Aleatorio.Next Take 3
在查询大量结果之前可能应该进行一些分析,但这对我的目的来说是完美的
答案 9 :(得分:0)
在LINQPad中使用LINQ to SQL,因为C#语句看起来像
IEnumerable<Customer> customers = this.ExecuteQuery<Customer>(@"SELECT top 10 * from [Customers] order by newid()");
customers.Dump();
生成的SQL是
SELECT top 10 * from [Customers] order by newid()
答案 10 :(得分:0)
下面的示例将调用源以检索计数,然后在源上应用跳过表达式,其数字介于0和n之间。第二种方法将使用随机对象(将命令内存中的所有内容)应用顺序,并选择传递给方法调用的数字。
public static class IEnumerable
{
static Random rng = new Random((int)DateTime.Now.Ticks);
public static T RandomElement<T>(this IEnumerable<T> source)
{
T current = default(T);
int c = source.Count();
int r = rng.Next(c);
current = source.Skip(r).First();
return current;
}
public static IEnumerable<T> RandomElements<T>(this IEnumerable<T> source, int number)
{
return source.OrderBy(r => rng.Next()).Take(number);
}
}
答案 11 :(得分:0)
我使用此方法获取随机新闻并且其工作正常;)
public string LoadRandomNews(int maxNews)
{
string temp = "";
using (var db = new DataClassesDataContext())
{
var newsCount = (from p in db.Tbl_DynamicContents
where p.TimeFoPublish.Value.Date <= DateTime.Now
select p).Count();
int i;
if (newsCount < maxNews)
i = newsCount;
else i = maxNews;
var r = new Random();
var lastNumber = new List<int>();
for (; i > 0; i--)
{
int currentNumber = r.Next(0, newsCount);
if (!lastNumber.Contains(currentNumber))
{ lastNumber.Add(currentNumber); }
else
{
while (true)
{
currentNumber = r.Next(0, newsCount);
if (!lastNumber.Contains(currentNumber))
{
lastNumber.Add(currentNumber);
break;
}
}
}
if (currentNumber == newsCount)
currentNumber--;
var news = (from p in db.Tbl_DynamicContents
orderby p.ID descending
where p.TimeFoPublish.Value.Date <= DateTime.Now
select p).Skip(currentNumber).Take(1).Single();
temp +=
string.Format("<div class=\"divRandomNews\"><img src=\"files/1364193007_news.png\" class=\"randomNewsImg\" />" +
"<a class=\"randomNews\" href=\"News.aspx?id={0}\" target=\"_blank\">{1}</a></div>",
news.ID, news.Title);
}
}
return temp;
}
答案 12 :(得分:0)
如果您使用 LINQPad ,请切换到 C#program 模式并执行以下操作:
void Main()
{
YourTable.OrderBy(v => Random()).FirstOrDefault.Dump();
}
[Function(Name = "NEWID", IsComposable = true)]
public Guid Random()
{
throw new NotImplementedException();
}
答案 13 :(得分:0)
var cust = (from c in ctx.CUSTOMERs.ToList() select c).OrderBy(x => x.Guid.NewGuid()).Taket(2);
选择随机2行
答案 14 :(得分:0)
添加到Marc Gravell的解决方案中。如果您没有使用datacontext类本身(因为您以某种方式代理它,例如伪造datacontext用于测试目的),您不能直接使用定义的UDF:它不会被编译为SQL,因为您没有在您的实际数据上下文类的子类或部分类。
此问题的解决方法是在代理中创建一个Randomize函数,并将其提供给您想要随机化的查询:
public class DataContextProxy : IDataContext
{
private readonly DataContext _context;
public DataContextProxy(DataContext context)
{
_context = context;
}
// Snipped irrelevant code
public IOrderedQueryable<T> Randomize<T>(IQueryable<T> query)
{
return query.OrderBy(x => _context.Random());
}
}
以下是您在代码中使用它的方法:
var query = _dc.Repository<SomeEntity>();
query = _dc.Randomize(query);
要完成,这是如何在FAKE datacontext(在内存实体中使用)中实现它:
public IOrderedQueryable<T> Randomize<T>(IQueryable<T> query)
{
return query.OrderBy(x => Guid.NewGuid());
}