Reputation: 2622
I have a requirement to filter a list of Clients based on if they haven't had any jobs booked in the last x months. In my code I have two lists, one is my Clients and the other is a filtered List of Jobs between today and x months ago and the idea is to filter Clients based on their id not appearing in the jobs list. I tried the following:
filteredClients.Where(n => jobsToSearch.Count(j => j.Client == n.ClientID) == 0).ToList();
But I seem to get ALL clients regardless. I can easily do a foreach but this severly slows down the process. How can I filter the client list based on the job list effectively?
Upvotes: 3
Views: 2227
Reputation: 415620
The main thing you're doing wrong is that you don't assign your results back to something. That's why your original seemed to keep all clients. But we can still improve on the original:
filteredClients = filteredClients.Where(n => !jobsToSearch.Any(j => j.Client == n.ClientId)).ToList();
The difference between this and your .Count()
solution is that .Any()
can stop looking at the jobs list with each client as soon as it encounters the first match, so it should run a bit faster. But we're not done yet. We can do even better by narrowing the jobs list down to only distinct clients:
var badClients = jobsToSearch.Select(j => j.Client).Distinct().ToList();
filteredClients = filteredClients.Where(n => !badClients.Any(j => j == n.ClientId)).ToList();
And likely even better still by using a HashSet, which can make O(1) lookups like a Dcitionary. Assuming the client ID is an int:
var badClients = new HashSet<int>(jobsToSearch.Select(j => j.Client));
filteredClients = filteredClients.Where(n => !badClients.Contains(n.ClientId)).ToList();
Whether this last option performs better depends on the number of clients that have jobs... if the list is short, the .Distinct() might still do better.
Finally, I don't normally recommend calling .ToList()
like this. As much as possible, save actually realizing a List, Array, or collection type until the last possible moment, and just keep it to an Enumerable for as long as possible.
Upvotes: 3
Reputation: 33809
To filter the clients who are in
IdList;
List1.Where(x=> IdList.Contains(x.ClientId));
To filter the clients who are not in
IdList;
List1.Where(x=> !IdList.Contains(x.ClientId));
Upvotes: 0
Reputation: 1205
did you thought about using "groupby"?
without checking the syntax and writing code out of my mind (havnt vs available atm):
var groupedJobs = jobsearch.GroupBy(job => job.Client);
var itemsWithJobs = filteredList.Where(item => groupedJobs.ContainsKey(item.ClientID));
I can check the syntax tomorrow morning.
The biggest pro of this is, that you have build an Dictonary which is much much faster to search in it. Than to iterate though lists.
Upvotes: 1