从 List<T> 中选择

3

我相信有一种简单的方法可以做到这一点(我猜测其中一种扩展方法?),但我在谷歌上找不到。

基本上,我有一个自定义类的列表;我想从中选择一些项目放入新列表中,其中一个属性等于另一个列表中的任何值。

这是我尝试做的事情的一个(简化的)快速示例:

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

2

Jez,

您可以尝试使用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();

这种方法可能会稍微冗长,但是也是另一种解决问题的方式。

[编辑] 此处已将其设置为新列表,而非选择的元素 - 真糊涂。


2

使用Intersect
若要使其与您的自定义比较方法一起工作,您需要在您的类中实现IEquatable<T>或创建一个新类来实现IEqualityComparer<T>,并将其传递给Intersect的重载方法。


1
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>将比较器作为第二个参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接