2012-12-17 4 views
3

У меня есть требование отфильтровать список Клиентов на основе, если у них не было заданий, забронированных за последние x месяцев. В моем коде у меня есть два списка, один из них - мои клиенты, а другой - отфильтрованный список вакансий между сегодняшним днем ​​и месяцем назад, и идея состоит в том, чтобы отфильтровать Клиенты на основе их идентификатора, не отображающегося в списке заданий. Я пробовал следующее:Отфильтровать список через другой

filteredClients.Where(n => jobsToSearch.Count(j => j.Client == n.ClientID) == 0).ToList(); 

Но я, кажется, ВСЕ ВСЕ клиенты. Я могу легко сделать foreach, но это значительно замедляет процесс. Как можно эффективно фильтровать список клиентов на основе списка заданий?

+0

являются j.Client и n.ClientID целыми числами? –

+0

Вы уверены, что запрос 'jobToSearch' верен? Ваш код выглядит так, как будто он должен делать то, что вы намерены делать. Если это не оптимизация, это тоже вам не поможет. –

+0

Вы никогда не присваиваете результаты ни к чему. '.Where()' возвращает новую последовательность. Он не изменяет существующую последовательность на месте. –

ответ

3

Главное, что вы делаете неправильно, так это то, что вы не возвращаете результаты к чему-то. Вот почему ваш оригинал, казалось, держал всех клиентов. Но мы все еще можем улучшить оригинал:

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) Lookups как в Dcitionary. Если предположить, что идентификатор клиента является INT:

var badClients = new HashSet<int>(jobsToSearch.Select(j => j.Client)); 
filteredClients = filteredClients.Where(n => !badClients.Contains(n.ClientId)).ToList(); 

ли выполняет это последний вариант лучше, зависит от количества клиентов, имеющих рабочие места ... если список короткий, .distinct() может еще лучше.

И, наконец, я обычно не рекомендую звонить .ToList() следующим образом. В максимально возможной степени сохраните фактическое представление списка, массива или типа коллекции до последнего момента и просто сохраните его в Enumerable как можно дольше.

+0

Я бы не стал беспокоиться о каком-либо заказе. В идеале, «badClients» просто превратился бы в какой-то поиск «O (1)» (либо через «ToLookup», «ToDictionary», либо просто создавая «HashSet»). В противном случае '! BadClients.Any (j => j == n.ClientId)' может быть 'O (n)' для каждого идентификатора клиента для тестирования. –

+1

Определенно hashset, так как нет данных: достаточно простое существование ключа. –

+1

На самом деле, мне это нравится, я собираюсь использовать его в ответе :) –

0

Отфильтровать клиентов, которые in IdList;

List1.Where(x=> IdList.Contains(x.ClientId)); 

Чтобы отфильтровать клиентов, которые not in список_идентификаторов;

List1.Where(x=> !IdList.Contains(x.ClientId)); 
1

Вы думаете об использовании «groupby»?

без проверки синтаксиса и написания кода из моего ума (havnt против имеющейся атм):

var groupedJobs = jobsearch.GroupBy(job => job.Client); 
var itemsWithJobs = filteredList.Where(item => groupedJobs.ContainsKey(item.ClientID)); 

я могу проверить синтаксис завтра утром.

Самый большой про это - это то, что вы построили диктонарий, который намного быстрее выполняет поиск в нем. Чем перебирать списки.

+1

+1 это именно это, но вместо 'GroupBy' использовать' ToLookup', а вместо 'ContainsKey' просто' Contains' (EDIT: If количество заданий с дублирующимися идентификаторами ClientID является особенно большим, тогда вы можете использовать 'var groupedJobs = new HashSet (jobsToSearch.Select (j => j.Client))' просто, чтобы избежать создания сгруппированных коллекций, которые в действительности не используются поскольку все, что нам действительно нужно, это поиск ClientID) –

+1

Идея заключалась не в том, чтобы потерять информацию о том, какие задания выполняются клиентом. Я думаю, когда ему нужно знать, будет ли там какая-либо работа, следующим требованием будет показать список заданий или, по крайней мере, счет. Но его не спрашивали ... так что HashSet был бы лучшим ответом ... вы правы =) –

+0

Чтобы прояснить, идея состоит в том, чтобы отфильтровать список Клиентов на основе того, были ли у них какие-либо задания за определенный период, Не нужно сохранять список заданий в конце, мне просто нужен отфильтрованный список клиентов. – user1166905

Смежные вопросы