4
votes

I would assume there's a simple LINQ query to do this, I'm just not exactly sure how. Please see code snippet below, the comment explains what I'd like to do:

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

6 Answers

10
votes

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

6
votes

You can do this using Where:

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

You can also use Intersect (var result = peopleList1.Intersect(peopleList2);), but that would need you to implement an extra IEqualityComparer<Person> or override Person's Equals and GetHashCode methods in a way that two Person instances with the same ID are regarded equal. Intersect would otherwise perform reference equality.

3
votes

I would join both lists on ID:

var inboth = from p1 in peopleList1
             join p2 in peopleList2
             on p1.ID equals p2.ID
             select p1;
List<Person> joinedList = inboth.ToList();

Related: Why is LINQ JOIN so much faster than linking with WHERE?

If you would override Equals + GetHashCode you could use Intersect:

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

or you could provide a custom IEqualityComparer<Person> for Intersect:

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;
    }
}

Now you can use it in this way:

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

Both, Enumerable.Join and Enumerable.Intersect are efficient since they are using a set.

1
votes
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
votes

You can use Enumerable.Intersect

var common = peopleList1.Intersect(peopleList2);
0
votes

You just can use the LINQ Intersect Extension Method.

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

So you would do it like that:

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);
  }
}

Just override the Equals Method in the Person-Class. I think you could compare the ids there.