Back to: LINQ Tutorial For Beginners and Professionals
LINQ SequenceEqual Method in C#
In this article, I am going to discuss LINQ SequenceEqual Method in C# with Examples. Please read our previous article where we discussed the LINQ DefaultIfEmpty Method in C# with Examples.
LINQ SequenceEqual Method in C#
The LINQ SequenceEqual Method in C# is used to check whether two sequences are equal or not. If two sequences are equal then it returns true else it returns false. Two sequences are considered to be equal when both the sequences have the same number of elements, as well as the same values, and should be present in the same order. There are two overloaded versions available for this SequenceEqual Method in LINQ. They are as follows.
As you can see the second overloaded versions take an extra IEqualityComparer parameter. So, whenever you don’t want the default comparer to be used by the LINQ SequenceEqual Method, you need to use this overloaded version to use your own comparer.
Example to Understand LINQ SequenceEqual Method in C#:
Let us see an example to understand LINQ SequenceEqual Method in C# using both method and query syntax. In the following example, we created two sequences to store the cities. As you can see both collections contains the same number of elements. Further, if you notice all the elements are present in the same order in both collections. So here the sequences are equal and the SequenceEqual method is going to return true. There is no such operator called SequenceEqual available in LINQ to write the query syntax, so, in that case, we can go with method syntax.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<string> cityList1 = new List<string> { "Delhi", "Mumbai", "Hyderabad" }; //Collection 1 or Sequenece 1 List<string> cityList2 = new List<string> { "Delhi", "Mumbai", "Hyderabad" }; //Checking if both Sequences are Equal or not //Using Method Syntax bool IsEqualMS = cityList1.SequenceEqual(cityList2); //Using Query Syntax bool IsEqualQS = (from city in cityList1 select city).SequenceEqual(cityList2); //Printing the Result Console.WriteLine(IsEqualQS); Console.ReadLine(); } } }
Output: True
Now, modify the example as follows. Here, we are having the same cities but with different cases. The default comparer which is used by the SequencesEqual method is case-sensitive. So, in the below example, it returns false as the values are case-sensitive.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<string> cityList1 = new List<string> { "DELHI", "mumbai", "Hyderabad" }; //Collection 1 or Sequenece 1 List<string> cityList2 = new List<string> { "delhi", "MUMBAI", "Hyderabad" }; //Checking if both Sequences are Equal or not //Using Method Syntax bool IsEqualMS = cityList1.SequenceEqual(cityList2); //Using Query Syntax bool IsEqualQS = (from city in cityList1 select city).SequenceEqual(cityList2); //Printing the Result Console.WriteLine(IsEqualQS); Console.ReadLine(); } } }
Output: False
Now, if you want the comparison to be case-insensitive, then you need to use the other overloaded version of the SequenceEqual() method which takes IEqualityComparer as a parameter. So, modify the Example as follows to use the second overloaded version of the SequenceEqual() method which takes IEqualityComparer. Here, you can see, we are passing StringComparer.OrdinalIgnoreCase is the second parameter to the SequenceEqual() method. The StringComparer class implements the IEqualityComparer interface.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<string> cityList1 = new List<string> { "DELHI", "mumbai", "Hyderabad" }; //Collection 1 or Sequenece 1 List<string> cityList2 = new List<string> { "delhi", "MUMBAI", "Hyderabad" }; //Checking if both Sequences are Equal or not //Using Method Syntax bool IsEqualMS = cityList1.SequenceEqual(cityList2, StringComparer.OrdinalIgnoreCase); //Using Query Syntax bool IsEqualQS = (from city in cityList1 select city).SequenceEqual(cityList2, StringComparer.OrdinalIgnoreCase); //Printing the Result Console.WriteLine(IsEqualMS); Console.ReadLine(); } } }
Output: True
Note: If you go to the definition of StringComparer class, then you will see that this class implements the IEqualityComparer interface.
What Happens if the Elements are not present in the same order?
If the Elements are not present in the same order in both sequences, then the SequenceEqual method is going to return False. In the following example, the SequenceEqual method returns false. This is because the elements are not present in the same order in both sequences.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<string> cityList1 = new List<string> { "Delhi", "Mumbai", "Hyderabad" }; //Collection 1 or Sequenece 1 List<string> cityList2 = new List<string> { "Delhi", "Hyderabad", "Mumbai" }; //Checking if both Sequences are Equal or not //Using Method Syntax bool IsEqualMS = cityList1.SequenceEqual(cityList2, StringComparer.OrdinalIgnoreCase); //Using Query Syntax bool IsEqualQS = (from city in cityList1 select city).SequenceEqual(cityList2, StringComparer.OrdinalIgnoreCase); //Printing the Result Console.WriteLine(IsEqualMS); Console.ReadLine(); } } }
Output: False
How we can Solve the above Problem?
If sequences contain the same data but in a different order, and you want the SequenceEqual method to return true, then, first you need to sort the data either in ascending or descending order in both the sequences and then only apply the LINQ SequenceEqual method which is shown in the below example.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<string> cityList1 = new List<string> { "Delhi", "Mumbai", "Hyderabad" }; //Collection 1 or Sequenece 1 List<string> cityList2 = new List<string> { "Delhi", "Hyderabad", "Mumbai" }; //Checking if both Sequences are Equal or not //Using Method Syntax bool IsEqualMS = cityList1.OrderBy(city => city).SequenceEqual(cityList2.OrderBy(city => city), StringComparer.OrdinalIgnoreCase); //Using Query Syntax bool IsEqualQS = (from city in cityList1.OrderBy(city => city) select city).SequenceEqual(cityList2.OrderBy(city => city), StringComparer.OrdinalIgnoreCase); //Printing the Result Console.WriteLine(IsEqualMS); Console.ReadLine(); } } }
Output: True
Working with Complex Type using LINQ SequenceEqual Method:
Let us understand how we can work with the LINQ SequenceEqual with Complex Data type in C#. To understand this, we are going to work with the following Student class. So, create a class file with the name Student.cs and then copy and paste the following code into it. Here you can see, we have created the Student class with two properties i.e. ID and Name. Then we have also created two methods i.e. GetStudents1 and GetStudents2. Further, if you notice these two methods are going to return the same data.
using System.Collections.Generic; namespace LINQSequenceEqualDemo { public class Student { public int ID { get; set; } public string Name { get; set; } public static List<Student> GetStudents1() { List<Student> listStudents = new List<Student>() { new Student{ID= 101,Name = "Preety"}, new Student{ID= 102,Name = "Priyanka"} }; return listStudents; } public static List<Student> GetStudents2() { List<Student> listStudents = new List<Student>() { new Student{ID= 101,Name = "Preety"}, new Student{ID= 102,Name = "Priyanka"} }; return listStudents; } } }
Now, what we will do is, we will check both the sequences which are returned by GetStudents1 and GetStudents2 method is the same or not using the LINQ SequenceEqual method. So, modify the Main method of the Program class as shown below.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<Student> StudentList1 = Student.GetStudents1(); //Collection 1 or Sequenece 1 List<Student> StudentList2 = Student.GetStudents2(); //Checking if both Sequences are Equal or not //Using Method Syntax bool IsEqualMS = StudentList1.SequenceEqual(StudentList2); //Using Query Syntax bool IsEqualQS = (from std in StudentList1 select std).SequenceEqual(StudentList2); //Printing the Result Console.WriteLine(IsEqualMS); Console.ReadLine(); } } }
Output: False
Even though both sequences contain the same data but we are getting the result as False. This is because when working with complex types, the default comparer which is used by the SequenceEqual method will only check if the object references are equal or not. It is not checking the object values, rather it is checking the object references and references are different in this case, and hence it returns False.
How to Solve the Above Problem?
How to Solve the Above Problem means how we can make sure the SequenceEqual method goes for value equality rather than reference equality i.e. we need to tell the SequenceEqual method to check the individual object values rather than object reference addresses. There are many ways we can solve the above problem. Some of them are as follows.
- Creating Custom Comparer. We need to use the other overloaded version of the SequenceEqual method to which we can pass a custom class that implements the IEqualityComparer interface.
- We need to Project the properties into a new anonymous type, which already overrides Equals() and GetHashCode() methods.
- Inside the Student class, we need to override the Equals() and GetHashCode() methods.
- By Implementing IEquatable<T> interface.
Creating Custom StudentComparer Class:
Create a class file with the name StudentComparer.cs and then copy and paste the following code into it. As you can see, this class implements the IEqualityComparer interface and provide the implementation for the Equals and GetHashCode methods.
using System.Collections.Generic; namespace LINQSequenceEqualDemo { public class StudentComparer : IEqualityComparer<Student> { public bool Equals(Student x, Student y) { return x.ID == y.ID && x.Name == y.Name; } public int GetHashCode(Student obj) { return obj.ID.GetHashCode() ^ obj.Name.GetHashCode(); } } }
Next, modify the Main method of the Program class as follows. Now, we need to create an instance of StudentComparer class and then we need to pass that instance to the SequenceEqual method which is shown in the below code. With these changes, now the comparer which we pass to the SequenceEqual method will be used to check the equality and this will use the individual object values, not the object reference.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<Student> StudentList1 = Student.GetStudents1(); //Collection 1 or Sequenece 1 List<Student> StudentList2 = Student.GetStudents2(); //Creating an Instance of StudentComparer StudentComparer studentComparer = new StudentComparer(); //Checking if both Sequences are Equal or not //Using Method Syntax //Passing the StudentComparer Instance to the SequenceEqual method bool IsEqualMS = StudentList1.SequenceEqual(StudentList2, studentComparer); //Using Query Syntax //Passing the StudentComparer Instance to the SequenceEqual method bool IsEqualQS = (from std in StudentList1 select std).SequenceEqual(StudentList2, studentComparer); //Printing the Result Console.WriteLine(IsEqualMS); Console.ReadLine(); } } }
Output: True
Using Anonymous Type with LINQ SequenceEqual Method:
In this approach, we need to select all the individual properties to an anonymous type. The following program does exactly the same thing. In the below example, we are projecting the data into an anonymous type.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<Student> StudentList1 = Student.GetStudents1(); //Collection 1 or Sequenece 1 List<Student> StudentList2 = Student.GetStudents2(); //Checking if both Sequences are Equal or not //Using Method Syntax //Projecting the Individual Properties to an Anonymous Type bool IsEqualMS = StudentList1 .Select(std => new { std.ID, std.Name }) .SequenceEqual(StudentList2.Select(std => new { std.ID, std.Name })); //Using Query Syntax //Projecting the Individual Properties to an Anonymous Type bool IsEqualQS = (from std in StudentList1 select new { std.ID, std.Name }) .SequenceEqual(StudentList2.Select( std => new { std.ID, std.Name })); //Printing the Result Console.WriteLine(IsEqualQS); Console.ReadLine(); } } }
Output: True
Overriding Equals() and GetHashCode() Methods within the Student Class
By default, any type (predefined or user-defined) is inherited from the Object class. That means the Student class is also inherited from the Object class. And, we also know that the Object class provides some virtual methods such as Equals() and GetHashCode(), etc. So, now, we need to override the Equals() and GetHashCode() methods of the Object class within the Student class. So, modify the Student class as shown below. Here, we are overriding the Equals() and GetHashCode() methods.
using System.Collections.Generic; namespace LINQSequenceEqualDemo { public class Student { public int ID { get; set; } public string Name { get; set; } public static List<Student> GetStudents1() { List<Student> listStudents = new List<Student>() { new Student{ID= 101,Name = "Preety"}, new Student{ID= 102,Name = "Priyanka"} }; return listStudents; } public static List<Student> GetStudents2() { List<Student> listStudents = new List<Student>() { new Student{ID= 101,Name = "Preety"}, new Student{ID= 102,Name = "Priyanka"} }; return listStudents; } //Overriding the Object class Equals Method public override bool Equals(object x) { return this.ID == ((Student)x).ID && this.Name == ((Student)x).Name; } //Overriding the Object class GetHashCode Method public override int GetHashCode() { return this.ID.GetHashCode() ^ this.Name.GetHashCode(); } } }
With the above changes in place, now modify the Main method of the Program class as shown below. Now, we need to use the overloaded version of the LINQ SequenceEqual method which does not take any parameter.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<Student> StudentList1 = Student.GetStudents1(); //Collection 1 or Sequenece 1 List<Student> StudentList2 = Student.GetStudents2(); //Checking if both Sequences are Equal or not //Using Method Syntax //Use the Overloaded version of the SequenceEqual method which does not take comparer parameter bool IsEqualMS = StudentList1.SequenceEqual(StudentList2); //Using Query Syntax //Use the Overloaded version of the SequenceEqual method which does not take comparer parameter bool IsEqualQS = (from std in StudentList1 select std) .SequenceEqual(StudentList2); //Printing the Result Console.WriteLine(IsEqualQS); Console.ReadLine(); } } }
Output: True
Implementing IEquatble<T> Interface in Student Class.
In this approach, we need to implement the IEquatble<T> Interface in Student Class and we need to implement the Equals Method of the IEquatble<T> Interface and we also need to override the GetHashCode method of the Object class. So, modify the Student class as shown below.
using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { public class Student : IEquatable<Student> { public int ID { get; set; } public string Name { get; set; } public static List<Student> GetStudents1() { List<Student> listStudents = new List<Student>() { new Student{ID= 101,Name = "Preety"}, new Student{ID= 102,Name = "Priyanka"} }; return listStudents; } public static List<Student> GetStudents2() { List<Student> listStudents = new List<Student>() { new Student{ID= 101,Name = "Preety"}, new Student{ID= 102,Name = "Priyanka"} }; return listStudents; } //Implementing the Equals Method of IEquatable Interface public bool Equals(Student other) { return this.ID.Equals(other.ID) && this.Name.Equals(other.Name); } //Overriding the Object class GetHashCode Method public override int GetHashCode() { return this.ID.GetHashCode() ^ this.Name.GetHashCode(); } } }
As you can see, here we have done two things. First, we implement the Equals method of the IEquatable interface and then we override the GetHashCode method of the Object class. With the above changes in place, now modify the Main Method of the Program class as shown below. Again, here, we need to use the overloaded version of the LINQ SequenceEqual method which does not take any parameter.
using System.Linq; using System; using System.Collections.Generic; namespace LINQSequenceEqualDemo { class Program { static void Main(string[] args) { //Collection 1 or Sequenece 1 List<Student> StudentList1 = Student.GetStudents1(); //Collection 1 or Sequenece 1 List<Student> StudentList2 = Student.GetStudents2(); //Checking if both Sequences are Equal or not //Using Method Syntax //Use the Overloaded version of the SequenceEqual method which does not take comparer parameter bool IsEqualMS = StudentList1.SequenceEqual(StudentList2); //Using Query Syntax //Use the Overloaded version of the SequenceEqual method which does not take comparer parameter bool IsEqualQS = (from std in StudentList1 select std) .SequenceEqual(StudentList2); //Printing the Result Console.WriteLine(IsEqualQS); Console.ReadLine(); } } }
Output: True
In the next article, I am going to discuss the LINQ Partitioning Methods in C# with Examples. In this article, I try to explain the LINQ SequenceEqual Method in C# with Examples. I hope you understood the need and use of the LINQ SequenceEqual Method in C#.