C# 使用LINQ通过一个属性比较两个列表

C# 使用LINQ通过一个属性比较两个列表,c#,linq,list,collections,C#,Linq,List,Collections,假设我有以下几点: class Widget1{ public int TypeID { get; set; } public string Color { get; set; } } class Widget2 { public int TypeID { get; set; } public string Brand { get; set; } } private void te

假设我有以下几点:

    class Widget1{
        public int TypeID { get; set; }
        public string Color { get; set; }
    }

    class Widget2
    {
        public int TypeID { get; set; }
        public string Brand { get; set; }
    }

    private void test()
    {
        List<Widget1> widgets1 = new List<Widget1>();
        List<Widget2> widgets2 = new List<Widget2>();
        List<Widget1> widgets1_in_widgets2 = new List<Widget1>();

        //some code here to populate widgets1 and widgets2

        foreach (Widget1 w1 in widgets1)
        {
            foreach (Widget2 w2 in widgets2)
            {
                if (w1.TypeID == w2.TypeID)
                {
                    widgets1_in_widgets2.Add(w1);
                }
            }
        }
    }
类Widget1{
公共int类型ID{get;set;}
公共字符串颜色{get;set;}
}
类Widget2
{
公共int类型ID{get;set;}
公共字符串品牌{get;set;}
}
专用无效测试()
{
List widgets1=新列表();
List widgets2=新列表();
List widgets1_in_widgets2=新列表();
//这里有一些用于填充widgets1和widgets2的代码
foreach(Widget1中的Widget1 w1)
{
foreach(Widget2中的Widget2 w2)
{
if(w1.TypeID==w2.TypeID)
{
widgets1_in_widgets2.添加(w1);
}
}
}
}
我使用两个foreach循环按TypeID比较列表,以填充第三个列表。
是否有其他方法使用LINQ通过TypeID比较这两个列表?也许是使用interselect或其他函数?

这里需要的是一个
连接

var widgets1_in_widgets2 = from first in widgest1
    join second in widgets2
    on first.TypeID equals second.TypeID
    select first;
Intersect
或多或少可以看作是
Join
的一种特殊情况,其中两个序列属于同一类型,因此可以应用于相等,而不需要为每种类型进行投影以生成一个键进行比较。考虑到您的情况,
Intersect
不是一个选项

如果某个特定ID在第二个集合中重复,并且您不希望该项在结果中重复,则可以使用
GroupJoin
而不是
Join

var widgets1_in_widgets2 = from first in widgest1
    join second in widgets2
    on first.TypeID equals second.TypeID
    into matches
    where matches.Any()
    select first;

Join的缺点是,如果widgets1或widgets2包含多个具有相同TypeID的元素(顺便说一句,这也适用于原始代码),则结果可能会重复

以下操作将完全满足您的要求:从widgets1返回所有元素,其中widgets2中存在具有相应TypeID的元素

widgets1_in_widgets2 = (from w1 in widgets1
                        where widgets2.Any(w2 => w1.TypeID == w2.TypeID)
                        select w1).ToList()
你可以这样做

widgets2.Where(y=>widget1.Any(z=>z.TypeID==y.TypeID));
尝试使用“Where”重载


我喜欢这个解决方案,因为它很容易读入代码

bool result = firstList.All(o => secondList.Any(w => w.Prop1 == o.Prop1 && w.Prop2 == o.Prop2));

请参阅fiddle中的完整示例:

虽然这将生成正确的输出,但当您在一个集合上对另一个集合中的每个项目进行线性搜索时,它的性能将相当差。
“Join的缺点是,如果widgets1或widgets2包含多个具有相同TypeID的元素,则结果可能会重复。
“OP中的代码实际上具有与
连接完全相同的输出,因此他在任一列表中没有重复的键,或者他想要重复的结果。@Servy:好的,我将在回答中提到这一点。尽管如此,变量命名还是让我认为这是无意的。如果这是您想要解决的问题,那么您可以简单地使用
GroupJoin
,它为您提供了所描述的解决方案,而不需要付出相当高的性能代价。还要注意的是,虽然我同意变量命名将表明他不希望结果中出现重复项,但他可能在第二个列表中没有重复项,因此不需要删除它们。+1“鉴于您的情况,Intersect不是一个选项”如果可以自定义
IEqualityComparer
,那么它将是一个选项,因此可以使用公共基类型。然后,您可以将其传递给或覆盖
BaseWidget
中的
Equals
+
GetHashCode
,以通过
TypeID
进行默认比较。虽然这将生成正确的输出,当您在一个集合上对另一个集合中的每个项目进行线性搜索时,它的性能会相当差。最简单的更改就是将其中一个集合的TypeID存储在一个可以更快搜索的
哈希集中。一个更重要的改变是只使用
Join
,正如我所展示的,尽管它最终会做几乎相同的事情。好的查询,在使用这个小列表时不应该是一个问题。好的和更快的一个答案只需要代码,不需要解释,特别是当问题在您更新此答案以指定其不同之处之前已得到彻底回答时。我发现这是一个有用的建议解决方案,在你想要比较顺序和避免任何线性搜索的情况下。Thx,这对我很有用。if(projectds.All(y=>r.ProjectsId.Any(z=>z.Equals(y))){reports.Add(r);}如果两个列表不同怎么办?
bool result = firstList.All(o => secondList.Any(w => w.Prop1 == o.Prop1 && w.Prop2 == o.Prop2));