我需要根据客户在过去x个月内是否没有预订任何工作来筛选客户列表。在我的代码中,我有两个列表,一个是我的客户端,另一个是从今天到x个月前的过滤作业列表,其想法是根据未出现在作业列表中的客户端id来过滤客户端。我尝试了以下方法:
filteredClients.Where(n => jobsToSearch.Count(j => j.Client == n.ClientID) == 0).ToList();
但我似乎得到了所有的客户。我可以很容易地做前臂,但这严重减慢了这个过程。如何根据工作列表有效地筛选客户列表?
您做错的主要事情是没有将结果分配回某个对象。这就是为什么你的原作似乎保留了所有的客户。但我们仍然可以在原来的基础上改进:
filteredClients = filteredClients.Where(n => !jobsToSearch.Any(j => j.Client == n.ClientId)).ToList();
这与.Count()
解决方案的区别在于,.Any()
可以在遇到第一个匹配时立即停止查看每个客户端的作业列表,因此它应该运行得更快。但我们还没有结束。我们可以通过将工作列表缩小到只有不同客户来做得更好:
var badClients = jobsToSearch.Select(j => j.Client).Distinct().ToList();
filteredClients = filteredClients.Where(n => !badClients.Any(j => j == n.ClientId)).ToList();
使用HashSet可能会更好,它可以使O(1)查找像Ddicional一样。假设客户端ID是int:
var badClients = new HashSet<int>(jobsToSearch.Select(j => j.Client));
filteredClients = filteredClients.Where(n => !badClients.Contains(n.ClientId)).ToList();
最后一个选项是否性能更好取决于拥有作业的客户端数量。。。如果列表很短,.Distinct()可能会做得更好。
最后,我通常不建议这样调用.ToList()
。尽可能地,将实际实现List、Array或集合类型保存到最后一刻,并尽可能长时间地将其保持为Enumerable。
您想过使用"groupby"吗?
不需要检查语法和编写代码(havnt与可用的atm):
var groupedJobs = jobsearch.GroupBy(job => job.Client);
var itemsWithJobs = filteredList.Where(item => groupedJobs.ContainsKey(item.ClientID));
明天早上我可以检查语法。
最大的好处是,你已经构建了一个Dictionary,它在里面搜索要比在列表中迭代快得多。
过滤in
IdList的客户端;
List1.Where(x=> IdList.Contains(x.ClientId));
过滤not in
IdList的客户端;
List1.Where(x=> !IdList.Contains(x.ClientId));