Выбрать из списка <T> - PullRequest
       27

Выбрать из списка <T>

3 голосов
/ 06 апреля 2011

Я уверен, что есть неправильный способ сделать это (я предполагаю, что один из методов расширения?), Но я пытаюсь найти его с помощью Google.

В основном у меня есть список пользовательских классов;Я хочу выбрать некоторые элементы из этого списка в новый список, где одно из свойств равно любому значению в другом списке.

Вот (упрощенный) быстрый пример того, что я пытаюсь сделать:

public class Job
    {
        public int Number;
        public string ClientCompanyName;            
    }

List<Job> lstJobs = new List<Job>();
List<Job> lstCompare = new List<Job>();

обычно я делал бы что-то вроде:

List<Job> lstFiltered = new List<Job>();
foreach(Job jobThis in lstCompare)
{
    foreach(jobComp in lstCompare)
    {
        if(jobThis.Number = jobComp.Number)
        {
            lstFiltered.Add(jobThis);
        }
    }
}

Есть ли метод расширения, который убирает этот последний бит в (в идеале) одну строку?

Приветствия

Ответы [ 4 ]

8 голосов
/ 06 апреля 2011

Вы можете использовать Intersect() для этого:

http://msdn.microsoft.com/en-us/library/bb460136.aspx

2 голосов
/ 06 апреля 2011

Еж,

Возможно, вы сможете использовать функцию LINQ intersect или попробовать:

var matches = from jobs in lstJobs
               join comp in lstCompare on jobs.Number equals comp.Number
               select jobs;

или синтаксис LINQ:

var matches = lstJobs.Join(lstCompare, jobs => jobs.Number,
                           comp => comp.Number, (jobs, comp) => jobs);

и вот версия reSharper, основанная на вашем оригинальном цикле:

List<Job> lstFiltered = (lstJobs.SelectMany(jobThis => lstCompare, 
                        (jobThis, jobComp) => new {jobThis, jobComp})
                        .Where(@t => @t.jobThis.Number == @t.jobComp.Number)
                        .Select(@t => @t.jobThis)).ToList();

слегка многословно, но еще один способ снять кожу с кошки.

[отредактировано] как указано в новом списке, а не в выбранных элементах - doh

2 голосов
/ 06 апреля 2011

Использование Intersect.
Чтобы он работал с вашим пользовательским сравнением, вам нужно либо внедрить IEquatable<T> в своем классе, либо создать новый класс, реализующий IEqualityComparer<T> для вашего класса, и передать его перегрузке Intersect.

1 голос
/ 06 апреля 2011
var lstFiltered = lstJobs
        .Where(job => lstCompare.Any(item => item.Number == job.Number))
        .ToList();

Приведенное выше решение хорошо работает, если число элементов в lstCompare мало. Для больших списков сравнения вы можете использовать некоторую коллекцию на основе хеша.

var compareSet = new HashSet<int>(lstCompare.Select(item => item.Number));
var lstFiltered = lstJobs
        .Where(job => compareSet.Contains(job.Number))
        .ToList();

Если условие сравнения является более сложным или требуется в нескольких местах, вы должны создать класс сравнения, который реализует IEqualityComparer<T>. Тогда вы можете использовать метод Intersect(), как уже предлагали другие. Однако это не является функционально идентичным с вышеупомянутыми решениями. Он возвращает только отдельные элементы, в то время как мои решения возвращают все соответствующие элементы. Это может быть значительная разница в некоторых приложениях.

Мой второй пример может быть легко изменен на использование IEqualityComparer<T> при необходимости. HashSet<T> принимает компаратор в качестве второго параметра.

...