Mar*_*tin 9 c# linq linq-to-objects
我们在使用LINQ的代码段中遇到了轻微的性能问题,并且提出了一个关于LINQ如何在查找方面工作的问题
我的问题是这个(请注意我已经更改了所有代码,因此这是代码的指示性示例,而不是真实场景):
特定
public class Person {
int ID;
string Name;
DateTime Birthday;
int OrganisationID;
}
Run Code Online (Sandbox Code Playgroud)
如果我有一个说100k Person对象的列表,然后是一个日期列表,比如1000,我运行了这段代码:
var personBirthdays = from Person p in personList
where p.OrganisationID = 123
select p.Birthday;
foreach (DateTime d in dateList)
{
if (personBirthdays.Contains(d))
Console.WriteLine(string.Format("Date: {0} has a Birthday", d.ToShortDateString()));
}
Run Code Online (Sandbox Code Playgroud)
结果代码将是以下迭代:
100k(用于查找具有organisationID 123的用户需要完成的循环)
乘以
1000(列表中的日期数量)
乘以
x(具有要检查的组织ID 123的用户数量的日期) )
这是很多迭代!
如果我将personBirthdays的代码更改为:
List<DateTime> personBirthdays =
(from Person p in personList
where p.OrganisationID = 123
select p.Birthday).ToList();
Run Code Online (Sandbox Code Playgroud)
这应该删除100k作为倍数,并只执行一次?
所以你会有100k +(1000*x)而不是(100k*1000*x).
问题是,这似乎太容易了,我确信LINQ在某个地方做了一些聪明的事情应该意味着这不会发生.
如果没有人回答,我会进行一些测试并报告.
清晰度更新:
我们不考虑数据库查找,该personList
对象是内存列表对象.这就是所有LINQ到对象.
这应该删除10k作为倍数,并只执行一次?
这意味着,不是迭代personList
100k次,而是为每个迭代执行where
和select
操作,你将迭代100k次,并且只对底层数据源执行一次和操作.List
where
select
问题是,这似乎太容易了,我确信LINQ在某个地方做了一些聪明的事情应该意味着这不会发生.
不,你的第一个查询只是你不应该使用LINQ做的事情,你应该采取查询的结果并将它们放入数据结构,如果你打算多次迭代它们(这是你改变的) .
您可以使用适当的数据结构进一步改进此查询.搜索a List
是相当低效的,因为它需要进行线性搜索.最好使用a HashSet
来存储查询的结果.A HashSet
在平均情况下具有O(1)搜索速度,而不是a的O(n)搜索时间List
.
var dates = new HashSet<DateTime>(from Person p in personList
where p.OrganisationID = 123
select p.Birthday);
foreach (DateTime d in dateList.Where(date => dates.Contains(date)))
{
Console.WriteLine(string.Format("Date: {0} has a Birthday", d.ToShortDateString()));
}
Run Code Online (Sandbox Code Playgroud)