In Byte-Sized #3 we are looking about the Intersect() method. Thats finds the common elements between two collections.

💡
Do not use two inner for-loops to find common elements in two sequences. Use Intersect() or IntersectBy() methods.

What is Intersect()

In LINQ , Intersect() is an operator to perform a set intersection of two sequences. It returns a new sequence that contains the elements common to both sequences, in other words, the elements that appear in both sequences.

The syntax for using the Intersect operator in LINQ is as follows:

var commonElements = sequence1.Intersect(sequence2);

Today I am going to introduce how to play with Intersect and the new syntaxes of this.

Simple sequences

You can use the Intersect operator to find the common elements between the two lists as follows:

List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };
List<int> list2 = new List<int> { 3, 4, 5, 6, 7 };

var list1list2Common = list1.Intersect(list2);

foreach (var item in list1list2Common)
{
    Console.WriteLine(item);
}

/*
3
4
5
*/

The result will be a new sequence containing the elements { 3, 4, 5 }, which are the elements that are common to both lists.

complex object sequences

Suppose you have a class Person that represents a person with a name and an age.

public class Person : IEquatable<Person>
{
    public string Name { get; set; }
    public int Age { get; set; }
}

And I used below List3 and List4 for describe examples

var list3 = new List<Person> 
{ 
    new Person { Name = "Alice", Age = 25 }, 
    new Person { Name = "Bob", Age = 30 }, 
    new Person { Name = "Charlie", Age = 35 },
    new Person { Name = "Eve", Age = 50 }
};

var list4 = new List<Person> 
{ 
    new Person { Name = "Bob", Age = 30 }, 
    new Person { Name = "David", Age = 35 }, 
    new Person { Name = "Eve", Age = 40 }
};

1. Using IEquatable<T>

To use Intersect with complex object lists, you can implement the IEquatable<T> interface on the class that represents the objects in the lists. The IEquatable<T> interface defines the Equals() method, which is used by the Intersect operator to compare the objects in the lists.

public class Person : IEquatable<Person>
{
    public string Name { get; set; }
    public int Age { get; set; }

    // override Equals method
    public bool Equals(Person other)
    {
        if (other == null) return false;
        return (this.Name == other.Name 
        			&& this.Age == other.Age);
    }
}

//...

var list3list4CommonEquatable = list3.Intersect(list4);

foreach (var item in list3list4CommonEquatable)
{
    Console.WriteLine(item.Name); // Bob
}

Here is the Sample code, and As the Name and Age, Bob is the common element in the sequence.

2. Using IEqualityComparer<T>

You can also use the Intersect operator on complex object lists by providing a custom IEqualityComparer<T> implementation that defines how to compare the objects in the lists.

I have created a custom PersonComparer class that implements the IEqualityComparer<Person> interface. This custom comparer defines how to compare two Person objects by implementing the Equals method, and how to calculate the hash code of a Person object by implementing the GetHashCode method.

public class PersonComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        if (x == null || y == null) return false;
        return (x.Name == y.Name && x.Age == y.Age);
    }

    public int GetHashCode(Person obj)
    {
        if (obj == null) return 0;
        return obj.Name.GetHashCode() 
        			^ obj.Age.GetHashCode();
    }
}

To use the Intersect operator on a list of Person objects, you can create two lists and a new instance of PersonComparer, and then call the Intersect method with the two lists and the custom comparer.

var comparer = new PersonComparer();

var commonPeople = list1.Intersect(list2, comparer);

IntersectBy() - New Implementation

Exisiting method  Intersect has been powered up by these new methods which can take a selector function to operate. This IntersectBy() was introduced with .NET 6 new linq features.

If we simply want to compare elements by key (Name), then we can use IntersectBy instead of creating comparer. Following code generates same output as using comparer.

// in this name is the key
var list3list4CommonSingleProperty 
	        = list3.IntersectBy(
            	list4.Select(o => o.Name), 
                x =>x.Name);

foreach (var item in list3list4CommonSingleProperty)
{
    Console.WriteLine(item.Name);
}

//Bob
//Eve

Here is an example of the showcase of how multiple properties can process like comparer. Here Age and Name are considered equality properties.

var list3list4CommonMultipleProperties 
		= list3
        .IntersectBy(list4.Select(o => new { name = o.Name, age = o.Age}),
         x => new {name = x.Name, age= x.Age});

foreach (var item in list3list4CommonMultipleProperties)
{
    Console.WriteLine(item.Name);
}

Conclusion

💫
The Intersect operator in LINQ is a powerful tool that allows developers to find the common elements between two collections. It can be used to simplify complex operations and save developers time and effort.

The IntersectBy is more powerful which can take a selector function to operate.


Resources

  1. Microsoft Documentation
  2. LINQ Intersect Method in C#

Demo Project

There is a demo project you can check out over on GitHub with the examples for Intersect() and IntersectBy().

GitHub - csandun/IntersectInLinq
Contribute to csandun/IntersectInLinq development by creating an account on GitHub.

💌
Put your comments on this topic. See ya soon on another blog post. 👊👊
Share this post