使用LINQ获取一个List<>中存在于另一个List<>中的项

5
我认为有一个简单的LINQ查询可以做到这一点,只是我不确定如何做。请参见下面的代码片段,注释解释了我想做的事情:
class Program
{
  static void Main(string[] args)
  {
    List<Person> peopleList1 = new List<Person>();
    peopleList1.Add(new Person() { ID = 1 });
    peopleList1.Add(new Person() { ID = 2 });
    peopleList1.Add(new Person() { ID = 3 });
    peopleList1.Add(new Person() { ID = 4});
    peopleList1.Add(new Person() { ID = 5});

    List<Person> peopleList2 = new List<Person>();
    peopleList2.Add(new Person() { ID = 1 });
    peopleList2.Add(new Person() { ID = 4});


    //I would like to perform a LINQ query to give me only
    //those people in 'peopleList1' that are in 'peopleList2'
    //this example should give me two people (ID = 1& ID = 4)
  }
}


  class Person
  {
     public int ID { get; set; }
  }
6个回答

11

var result = peopleList2.Where(p => peopleList1.Any(p2 => p2.ID == p.ID));

这段代码使用了C#的Lambda表达式语法,意思是从peopleList2中选择那些在peopleList1中有相同ID的人。

8
您可以使用 Where 来实现此操作:
var result = peopleList1.Where(p => peopleList2.Any(p2 => p2.ID == p.ID));

您还可以使用Intersectvar result = peopleList1.Intersect(peopleList2);),但这需要您实现额外的IEqualityComparer<Person>或以一种使两个具有相同IDPerson实例被视为相等的方式覆盖PersonEqualsGetHashCode方法。Intersect否则将执行引用相等性。


5
我会通过ID将这两个列表联接起来:
var inboth = from p1 in peopleList1
             join p2 in peopleList2
             on p1.ID equals p2.ID
             select p1;
List<Person> joinedList = inboth.ToList();

相关内容:为什么LINQ JOIN比使用WHERE连接要快得多?

如果您重写EqualsGetHashCode,则可以使用Intersect

List<Person> joinedList = peopleList1.Intersect(peopleList2).ToList();

或者你可以为Intersect提供一个自定义的IEqualityComparer<Person>

public class  PersonIdComparer: IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        if(object.ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;

        return x.ID == y.ID;
    }

    public int GetHashCode(Person obj)
    {
        return obj == null ? int.MinValue : obj.ID;
    }
}

现在你可以这样使用它:
List<Person> joinedList = peopleList1
     .Intersect(peopleList2, new PersonIdComparer())
     .ToList();

Enumerable.JoinEnumerable.Intersect都是高效的,因为它们使用了一个集合。


1
这是最好的答案。可悲的是,从投票结果来看,没有人关心效率和正确的做事方式。他们想要的只是更短、更简单的方法。可怜的软件用户:( +1 - Ivan Stoev

1
Product[] fruits1 = { new Product { Name = "apple", Code = 9 }, 
                           new Product { Name = "orange", Code = 4 },
                            new Product { Name = "lemon", Code = 12 } };

    Product[] fruits2 = { new Product { Name = "apple", Code = 9 } };

    //Get all the elements from the first array
    //except for the elements from the second array.

    IEnumerable<Product> except =
        fruits1.Except(fruits2);

    foreach (var product in except)
        Console.WriteLine(product.Name + " " + product.Code);

    /*
      This code produces the following output:

      orange 4
      lemon 12
    */

0

你可以使用LINQ的Intersect扩展方法。

http://msdn.microsoft.com/en-us/library/bb460136(v=VS.100).aspx

你可以这样做:

class Program
{
  static void Main(string[] args)
  {
    List<Person> peopleList1 = new List<Person>();
    peopleList1.Add(new Person() { ID = 1 });
    peopleList1.Add(new Person() { ID = 2 });
    peopleList1.Add(new Person() { ID = 3 });
    peopleList1.Add(new Person() { ID = 4});
    peopleList1.Add(new Person() { ID = 5});

    List<Person> peopleList2 = new List<Person>();
    peopleList2.Add(new Person() { ID = 1 });
    peopleList2.Add(new Person() { ID = 4});

    var result = peopleList1.Intersect(peopleList2);
  }
}

只需在Person类中覆盖Equals方法。我认为你可以在那里比较ids。

@RenéVogt 谢谢,我没有完全考虑到这一点。但我已经将其添加到答案中了。 :) - Marius

0

1
如果您不覆盖 EqualsGetHashCode,它就无法工作,因此目前并没有什么帮助。 - Tim Schmelter
2
只有当Person类有一个重写的Equals方法,该方法定义了如果两个Person实例的ID相等,则它们相等,才能起作用。 - René Vogt
@RenéVogt:Intersect 在调用 Equals 之前先使用 GetHashCode - Tim Schmelter
是的,这就是为什么提供 Intersect 的完整实现链接 :) - huMpty duMpty

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