SequenceEqual Operator in LINQ

by Sachin Singh


Posted on Saturday, 06 February 2021

Tags: SequenceEqual Operator in LINQ

SequenceEqual is the only Equality operator available in LINQ. The SequenceEqual method checks whether two Collections are equal or not and accordingly returns true or false. If the two sequence or collections are equal then it will return true otherwise will return false.

The collections of primitive data types (string , int, float etc) are considered as equal based on following conditions
  1. Both the sequences should have the same number of elements and
  2. Same values should be present in the same order in both the sequences

The collection with complex type elements are considered as equal if the objects of the collection have same reference otherwise they are considered as not equal.

Let's check how does the SequenceEqual method behaves with the collection of primitive data types.

Example 1: Compare two Lists of string


  IList<string> strList1 = new List<string>(){"apple", "banana", "mango", "guava", "grapes"};
  IList<string> strList2 = new List<string>(){"apple", "banana", "mango", "guava", "grapes"};
 bool isEqual = strList1.SequenceEqual(strList2); // returns true
 Console.WriteLine(isEqual);

If the order of elements are not the same then SequenceEqual method returns false.

Example 2: SequenceEqual returns false if order of elements are not same.


 IList<string> strList1 = new List<string>()>(){"apple", "banana", "mango", "guava", "grapes"};
 IList<string> strList2 = new List<string>()>(){"banana", "apple", "mango", "guava", "grapes"};
 bool isEqual = strList1.SequenceEqual(strList2); // returns false
 Console.WriteLine(isEqual);

Example 3 : In this case, SequenceEqual() returns false beacuse the elements with difference in case are considered as not equal, this means that the SequenceEqual does the default comparison which is case sensitive.


 IList<string> strList1 = new List<string>()>(){"apple", "banana", "mango", "guava", "grapes"};
 IList<string> strList2 = new List<string>()>(){"Apple", "Banana", "Mango", "Guava", "Grapes"};
 var result = strList1.SequenceEqual(strList2);
 Console.WriteLine("Are Equal = " + result);

Example 4: By-default the comparision is case-sensitive, in order to perform a case-insensitive comparision, we can use the other overload of SequenceEqual() method which accepts an additional parameter in the form of alternate comparer.


 IList<string> strList1 = new List<string>()>(){"apple", "banana", "mango", "guava", "grapes"};
 IList<string> strList2 = new List<string>()>(){"Apple", "Banana", "Mango", "Guava", "Grapes"};
 var result = strList1.SequenceEqual(strList2, StringComparer.OrdinalIgnoreCase);
 Console.WriteLine("Are Equal = " + result);

Comparing Collection of Complex Objects

 SequenceEqual operator for collection of complex objects
SequenceEqual operator for collection of complex objects

As you can see in the diagram above ,the SequenceEqual extension method checks the references of two objects to determine whether two sequences are equal or not. This may give wrong result. Consider following example:

Example5 : SequenceEqual returns false for different objects even if they contain same values.


 Employee emp1 = new Employee() { Id = 1, Name = "Sachin" };
 Employee emp2 = new Employee() { Id = 2, Name = "Arjun" };
 List<Employee> employeeList1 = new List<Employee>(){ emp1,emp2 };
 List<Employee> employeeList2 = new List<Employee>(){ emp1,emp2 };      
 bool isEqual = employeeList1.SequenceEqual(employeeList2); // returns true
 Employee emp3 = new Employee(){ Id = 1, Name = "Sachin" };
 Student emp4 = new Employee(){ Id = 2, Name = "Arjun" };
 List<Employee> employeeList3 = new List<Employee>(){emp3,emp4};       
 isEqual = employeeList1.SequenceEqual(employeeList3);// returns false

In the above example, employeeList1 and employeeList2 contains the same employee objects. So employeeList1.SequenceEqual(employeeList2) returns true. But, employeeList3 contains different Employee objects. So now, employeeList1.SequenceEqual(employeeList3) will return false even if Id and Name properties contain the same value.

To solve the problem in Example 5, there are 3 ways
  1. The first method is to use the other overloaded version of SequenceEqual() method to which we can pass a custom class that implements IEqualityComparer
  2. The second way is to Override Equals() and GetHashCode() methods in the corresponding class
  3. And the third and most accurate way is to project the properties into a new anonymous type, which overrides Equals() and GetHashCode() methods

Method 1 Implementing IEqualityComparer


 class EmployeeComparer : IEqualityComparer
  {
    public bool Equals(Employee x, Employee y)
    {
        if (x.Id == y.Id && x.Name.ToLower() == y.Name.ToLower())
            return true;
        return false;
    }

    public int GetHashCode(Student obj)
    {
        return obj.GetHashCode();
    }
 }

Now, you can use above EmployeeComparer class in SequenceEqual extension method as a second parameter to compare the values.


  bool isEqual = employeeList1.SequenceEqual(employeeList2, new EmployeeComparer());

Method II. Override Equals() and GetHashCode() methods in Employee class


  public class Employee
  {
    public int ID { get; set; }
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        return this.ID == ((Employee)obj).ID && this.Name == ((Employee)obj).Name;
    }

    public override int GetHashCode()
    {
        return this.ID.GetHashCode() ^ this.Name.GetHashCode();
    }
 }
 Employee emp1 = new Employee() { Id = 1, Name = "Sachin" };
 Employee emp2 = new Employee() { Id = 2, Name = "Arjun" };
 Employee emp3 = new Employee(){ Id = 1, Name = "Sachin" };
 Student emp4 = new Employee(){ Id = 2, Name = "Arjun" };
 List<Employee> employeeList1 = new List<Employee>(){ emp1,emp2 };
 List<Employee> employeeList2 = new List<Employee>(){emp3,emp4};      
 isEqual = employeeList1.SequenceEqual(employeeList2);// returns true

Method 3. Project the properties into a new anonymous type, which overrides Equals() and GetHashCode() methods


 Employee emp1 = new Employee() { Id = 1, Name = "Sachin" };
 Employee emp2 = new Employee() { Id = 2, Name = "Arjun" };
 Employee emp3 = new Employee(){ Id = 1, Name = "Sachin" };
 Student emp4 = new Employee(){ Id = 2, Name = "Arjun" };
 List<Employee> employeeList1 = new List<Employee>(){ emp1,emp2 };
 List<Employee> employeeList2 = new List<Employee>(){emp3,emp4};      
 isEqual = employeeList1.Select(x=>new {x.Id,x.Name}).SequenceEqual(employeeList2.Select(x=>new{x.Id,X.Name}));// returns true

Obviously the third method is the easiest and most efficient.

Points to Remember :
  1. The SequenceEqual method compares the number of items, and their values for primitive data types.
  2. The SequenceEqual method compares the reference of objects or items for complex types.
  3. We need to create a class that implements the IEqualityComparer interface and passes it to the SequenceEqual method to compare two collections of complex types.

This is how use LINQ SequenceEqual method to check the equality of two collections.