C# - 根据与另一个列表(Linq + Lambda)的部分交集从列表中选择特定项目

Omr*_*mri 3 .net c# linq lambda

我有两个清单:

List<objA> list1
List<objB> list2

class objA
{
   string Name;
}

class objB
{
   string Name;
   bool SomeProp;
}
Run Code Online (Sandbox Code Playgroud)

使用C#linq/lambda我想选择所有objA对象,其Name属性等于第二个obj(list1.Name == list2.Name)的name属性,并检查objB的另一个属性(list2.SomeProp == true ).

Ser*_*kiy 7

我建议使用join:

from a in list1
join b in list2 on a.Name equals b.Name
where b.SomeProp
select a
Run Code Online (Sandbox Code Playgroud)

Lambda语法:

list1.Join(listb.Where(b => b.SomeProp),
           a => a.Name, b => b.Name, (a,b) => a)
Run Code Online (Sandbox Code Playgroud)

注意:因此,您将避免枚举list1中每个项目的list2集合(解决方案Any)


为了显示两个解决方案之间的区别 - 让我们看看在将linq转换为plain循环后它们的样子.首先是

list1.Where(a => list2.Any(b => b.Name == a.Name && b.SomeProp))
Run Code Online (Sandbox Code Playgroud)

它相当于

foreach(var a in list1)
{
   foreach(var b in list2)
   {
       if (a.Name == b.Name && b.SomeProp)
       {
           yield return a;
           break;
       }
   }
} 
Run Code Online (Sandbox Code Playgroud)

如您所见 - 它具有嵌套循环,复杂度为O(N*M).通过join,我们为内部序列创建了Lookup:

Lookup<string, objB> lookup = list2.Where(b => b.SomeProp).ToLookup(b => b.Name);

foreach(var a in list1)
{
    Grouping<string, objB> g = lookup.GetGrouping(a.Name);
    if (g == null)
       continue;

    foreach(var b in g)
       yield return a;
}
Run Code Online (Sandbox Code Playgroud)

这里的区别是在查找中搜索 - 这是O(1)操作.总复杂度为O(M + N)