LINQ is a powerful feature in C# that allows developers to query and manipulate data from various sources using a uniform syntax. One of the useful methods provided by LINQ is the Except method, which allows you to find the set difference between two sequences. In this article, we will explore the Except method and provide examples to help you understand its usage.
Â
Understanding the LINQ Except Method
The LINQ Except Method is used to return the elements which are present in the first data source but not in the second data source. It is a LINQ query method that takes two collections as input and returns a new collection that contains the elements of the first collection that are not present in the second collection. The syntax for using the Except
method is as follows:
1 2 3 |
var result = firstSequence.Except(secondSequence); |
Â
What happens if any of the sequences is null?
The Except Method will throw an exception if any of the sequences is null. In the below example, the second sequence is null and while performing the Except operation using the Except Method it will throw an exception.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using System; using System.Collections.Generic; using System.Linq; namespace LINQDemo { class Program { static void Main(string[] args) { List<int> dataSource1 = new List<int>() { 1, 2, 3, 4, 5, 6 }; List<int> dataSource2 = null; //Method Syntax var MS = dataSource1.Except(dataSource2).ToList(); foreach (var item in MS) { Console.Write(item + " "); } Console.ReadKey(); } } } |
Now run the application and you will get the following exception: System.ArgumentNullException: 'Value cannot be null. (Parameter 'second')'
Â
Understand LINQ Except Method with String Data Type
In the below example, I am showing how to use LINQ Except Method with String Data using both Method and Query Syntax. Here, we have a string array of countries and we need to return the countries from the first collection, that are not present in the second collection using Except Method. So, modify the Main Method of the Program class as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using System; using System.Linq; namespace LINQDemo { class Program { static void Main(string[] args) { string[] dataSource1 = { "India", "USA", "UK", "Canada", "Srilanka" }; string[] dataSource2 = { "India", "uk", "Canada", "France", "Japan" }; //Method Syntax var MS = dataSource1.Except(dataSource2).ToList(); //Query Syntax var QS = (from country in dataSource1 select country) .Except(dataSource2).ToList(); foreach (var item in QS) { Console.WriteLine(item); } Console.ReadKey(); } } } |
In spite of having the country UK in the second collection, it still shows in the output. This is because the default comparer that is being used to filter the data by the Except Method is case-insensitive. So if you want to ignore the case-sensitive, then you need to use the other overloaded version of the Except() method which takes IEqualityComparer as an argument. So, modify the Main Method of the Program as shown below. Here, we are passing StringComparer as an argument and this StringComparer class already implements the IEqualityComparer interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using System; using System.Linq; namespace LINQDemo { class Program { static void Main(string[] args) { string[] dataSource1 = { "India", "USA", "UK", "Canada", "Srilanka" }; string[] dataSource2 = { "India", "uk", "Canada", "France", "Japan" }; //Method Syntax var MS = dataSource1.Except(dataSource2, StringComparer.OrdinalIgnoreCase).ToList(); //Query Syntax var QS = (from country in dataSource1 select country) .Except(dataSource2, StringComparer.OrdinalIgnoreCase).ToList(); foreach (var item in MS) { Console.WriteLine(item); } Console.ReadKey(); } } } |
LINQ Except() Method with Complex Type in C#:
The LINQ Except() Method in C# works slightly different manner when working with complex types such as Employee, Product, Student, etc. Let us understand this with an example. Create a class file with the name Student.cs and then copy and paste the following code into it.
1 2 3 4 5 6 7 8 9 10 |
namespace LINQDemo { public class Student { public int ID { get; set; } public string Name { get; set; } } } |
This is a very simple student class with just two properties. Let’s say, we have the following two data sources.
As you can, we have two data sources. The first data source i.e. AllStudents holds the information of all the students while the second data source i.e. Class6Students holds the data of only the 6th-class students. Now, our requirement is only to fetch all the student names except the 6th-class students. That means we need to fetch the student names from the AllStudents data source which are not present in the second data source i.e. Class6Students.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
using System; using System.Linq; using System.Collections.Generic; namespace LINQDemo { class Program { static void Main(string[] args) { List<Student> AllStudents = new List<Student>() { new Student {ID = 101, Name = "Preety" }, new Student {ID = 102, Name = "Sambit" }, new Student {ID = 103, Name = "Hina"}, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, new Student {ID = 106, Name = "Santosh"}, }; List<Student> Class6Students = new List<Student>() { new Student {ID = 102, Name = "Sambit" }, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, }; //Method Syntax var MS = AllStudents.Select(x => x.Name).Except(Class6Students.Select(y => y.Name)).ToList(); //Query Syntax var QS = (from std in AllStudents select std.Name).Except(Class6Students.Select(y => y.Name)).ToList(); foreach (var name in MS) { Console.WriteLine(name); } Console.ReadKey(); } } } |
Now we need to select all the information of all the students from the first data source which is not present in the second data source. Let us modify the Main Method of the program class as shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
using System; using System.Linq; using System.Collections.Generic; namespace LINQDemo { class Program { static void Main(string[] args) { List<Student> AllStudents = new List<Student>() { new Student {ID = 101, Name = "Preety" }, new Student {ID = 102, Name = "Sambit" }, new Student {ID = 103, Name = "Hina"}, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, new Student {ID = 106, Name = "Santosh"}, }; List<Student> Class6Students = new List<Student>() { new Student {ID = 102, Name = "Sambit" }, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, }; //Method Syntax var MS = AllStudents.Except(Class6Students).ToList(); //Query Syntax var QS = (from std in AllStudents select std).Except(Class6Students).ToList(); foreach (var student in MS) { Console.WriteLine($" ID : {student.ID} Name : {student.Name}"); } Console.ReadKey(); } } } |
Â
Using Anonymous Type with Except Method in C#:
In this approach, we need to select all the individual properties to an anonymous type. The following program does exactly the same thing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
using System; using System.Linq; namespace LINQDemo { class Program { static void Main(string[] args) { List<Student> AllStudents = new List<Student>() { new Student {ID = 101, Name = "Preety" }, new Student {ID = 102, Name = "Sambit" }, new Student {ID = 103, Name = "Hina"}, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, new Student {ID = 106, Name = "Santosh"}, }; List<Student> Class6Students = new List<Student>() { new Student {ID = 102, Name = "Sambit" }, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, }; //Method Syntax var MS = AllStudents.Select(x => new { x.ID, x.Name }) .Except(Class6Students.Select(x => new { x.ID, x.Name })).ToList(); //Query Syntax var QS = (from std in AllStudents select new { std.ID, std.Name }) .Except(Class6Students.Select(x => new { x.ID, x.Name })).ToList(); foreach (var student in QS) { Console.WriteLine($" ID : {student.ID} Name : {student.Name}"); } Console.ReadKey(); } } } |
Â
Using IEqualityComparer Comparer with LINQ Except Method in C#:
In this approach, we need to create a class and then we need to implement the IEqualityComparer interface and we need to implement the Equals and GetHashCode method. So, create a class file with the name StudentComparer.cs and then copy and paste the following code into it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
using System.Collections.Generic; using System; namespace LINQDemo { public class StudentComparer : IEqualityComparer<Student> { public bool Equals(Student x, Student y) { //First check if both object reference are equal then return true if(object.ReferenceEquals(x, y)) { return true; } //If either one of the object refernce is null, return false if (object.ReferenceEquals(x,null) || object.ReferenceEquals(y, null)) { return false; } //Comparing all the properties one by one return x.ID == y.ID && x.Name == y.Name; } public int GetHashCode(Student obj) { //If obj is null then return 0 if (obj == null) { return 0; } //Get the ID hash code value int IDHashCode = obj.ID.GetHashCode(); //Get the Name HashCode Value int NameHashCode = obj.Name == null ? 0 : obj.Name.GetHashCode(); return IDHashCode ^ NameHashCode; } } } |
Next, we need to create an instance of StudentComparer class and need to pass that instance to the Except method. So, modify the Main method of the Program class as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
using System.Collections.Generic; using System; using System.Linq; namespace LINQDemo { class Program { static void Main(string[] args) { List<Student> AllStudents = new List<Student>() { new Student {ID = 101, Name = "Preety" }, new Student {ID = 102, Name = "Sambit" }, new Student {ID = 103, Name = "Hina"}, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, new Student {ID = 106, Name = "Santosh"}, }; List<Student> Class6Students = new List<Student>() { new Student {ID = 102, Name = "Sambit" }, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, }; //Create an instance of StudentComparer StudentComparer studentComparer = new StudentComparer(); //Method Syntax var MS = AllStudents .Except(Class6Students, studentComparer).ToList(); //Query Syntax var QS = (from std in AllStudents select std) .Except(Class6Students, studentComparer).ToList(); foreach (var student in MS) { Console.WriteLine($" ID : {student.ID} Name : {student.Name}"); } Console.ReadKey(); } } } |
Now run the application and it should display the output as expected as shown in the below image.
Â
Overriding Equals() and GetHashCode() Methods within the Student Class
In C#.NET, 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(). 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
namespace LINQDemo { public class Student { public int ID { get; set; } public string Name { get; set; } public override bool Equals(object obj) { //As the obj parameter type is object, so we need to //cast it to Student Type return this.ID == ((Student)obj).ID && this.Name == ((Student)obj).Name; } public override int GetHashCode() { //Get the ID hash code value int IDHashCode = this.ID.GetHashCode(); //Get the string HashCode Value //Check for null refernece exception int NameHashCode = this.Name == null ? 0 : this.Name.GetHashCode(); return IDHashCode ^ NameHashCode; } } } |
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 Except method which does not take any parameter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
using System.Collections.Generic; using System; using System.Linq; namespace LINQDemo { class Program { static void Main(string[] args) { List<Student> AllStudents = new List<Student>() { new Student {ID = 101, Name = "Preety" }, new Student {ID = 102, Name = "Sambit" }, new Student {ID = 103, Name = "Hina"}, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, new Student {ID = 106, Name = "Santosh"}, }; List<Student> Class6Students = new List<Student>() { new Student {ID = 102, Name = "Sambit" }, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, }; //Method Syntax var MS = AllStudents .Except(Class6Students).ToList(); //Query Syntax var QS = (from std in AllStudents select std) .Except(Class6Students).ToList(); foreach (var student in QS) { Console.WriteLine($" ID : {student.ID} Name : {student.Name}"); } Console.ReadKey(); } } } |
Now execute the above program and it will display the output as expected as shown in the below image.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
using System; namespace LINQDemo { public class Student : IEquatable<Student> { public int ID { get; set; } public string Name { get; set; } public bool Equals(Student other) { return this.ID.Equals(other.ID) && this.Name.Equals(other.Name); } public override int GetHashCode() { int IDHashCode = this.ID.GetHashCode(); int NameHashCode = this.Name == null ? 0 : this.Name.GetHashCode(); return IDHashCode ^ NameHashCode; } } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
using System.Collections.Generic; using System; using System.Linq; namespace LINQDemo { class Program { static void Main(string[] args) { List<Student> AllStudents = new List<Student>() { new Student {ID = 101, Name = "Preety" }, new Student {ID = 102, Name = "Sambit" }, new Student {ID = 103, Name = "Hina"}, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, new Student {ID = 106, Name = "Santosh"}, }; List<Student> Class6Students = new List<Student>() { new Student {ID = 102, Name = "Sambit" }, new Student {ID = 104, Name = "Anurag"}, new Student {ID = 105, Name = "Pranaya"}, }; //Method Syntax var MS = AllStudents .Except(Class6Students).ToList(); //Query Syntax var QS = (from std in AllStudents select std) .Except(Class6Students).ToList(); foreach (var student in QS) { Console.WriteLine($" ID : {student.ID} Name : {student.Name}"); } Console.ReadKey(); } } } |
Run the application and you should see the output as expected as shown in the below image.
In the next article, I am going to discuss the LINQ Intersect Method in C# with Examples. In this article, I try to explain the LINQ Except Method in C# with Examples. I hope you enjoy this article and understand the Concept of LINQ Except Method in C# with Examples.
Leave a Comment