LinQ Operation

Introduction

Hi everybody, here in this article I want to raise a few basic things regarding the Distinct() extension method in “System.Linq” and we will explain how to customize our Distinct() method using "IEqualityComparer".

Creating Console Application

Let's create a console application for me its “UnderstandingDistinct” and let's create a custom class called “Student” with the following properties:

public class Student

{

    public int StudentID { get; set; }

    public string StudentName { get; set; }

    public string Country { get; set; }

    public string City { get; set; }

}

Let's go ahead and do a distinct operation on the collection of the student objects. The following is the code to create a collection of custom objects and do a Distinct() operation in program.cs.

class Program

{

    static void Main(string[] args)

    {

        var studentList = new List<Student>()

        {

            new Student{ StudentID = 1, City = "BBSR", Country = "India", StudentName = "Mukesh" },

            new Student{ StudentID = 2, City = "BBSR", Country = "India", StudentName = "Abhishek"},

            new Student{ StudentID = 3, City = "BBSR", Country = "India", StudentName = "Sachin"},

            new Student{ StudentID = 4, City = "BLR", Country = "India", StudentName = "Richi"},

            new Student{ StudentID = 5, City = "BLR", Country = "India", StudentName = "Nibedita"},               

        }; 

        var distinctStudentList = studentList.Distinct();           

        //Looping through student list

        foreach (var stud in distinctStudentList)

        {

            Console.WriteLine(stud.StudentName);

        }

    }

}

On execution of the program we will get the following output:



That's normal, but let's suppose we have a scenario where we want to have all student objects with a distinct country and city from the list. We can see in the editor itsef that we have 2 extensions to this distinct extension method and they are as follows:
 
extension method
 


And to have a distinct collection on country and city we can use the second extension but before using that we need to create our own custom IEqualityComparer. Let's create a class named “StudentComparer” and this class must implement “IEqualityComparer”. Finally the class will look like:
 

public class StudentComparer : IEqualityComparer<Student>

{

    public bool Equals(Student x, Student y)

    {           

    } 

    public int GetHashCode(Student obj)

    {          

     }

}

The “IEqualityComparer” interface implements the 2 functions “bool Equals(Student x, Student y)” and “int GetHashCode(Student obj)” and these 2 functions decide the equality between student objects. Since we are trying to have distinct on 2 factors that are the country and city properties of a student object, let's add our logic to these 2 functions and our custom logic will look like:

public class StudentComparer : IEqualityComparer<Student>

{

    public bool Equals(Student x, Student y)

    {

        return x.Country.Equals(y.Country) && x.City.Equals(y.City);

     }

    public int GetHashCode(Student obj)

    {

        var countryHashCode = obj.Country.GetHashCode();

        var cityHashCode = obj.City.GetHashCode();

        return countryHashCode ^ cityHashCode;

    }

}

So our custom equality comparer is ready. Let's use the second Distinct() extension in program.cs as in the following:

class Program

{

    static void Main(string[] args)

    {

        var studentList = new List<Student>()

        {

                new Student{ StudentID = 1, City = "BBSR", Country = "India", StudentName = "Mukesh" },

                new Student{ StudentID = 2, City = "BBSR", Country = "India", StudentName = "Abhishek"},

                new Student{ StudentID = 3, City = "BBSR", Country = "India", StudentName = "Sachin"},

                new Student{ StudentID = 4, City = "BLR", Country = "India", StudentName = "Richi"},

                new Student{ StudentID = 5, City = "BLR", Country = "India", StudentName = "Nibedita"}               

        };

        var distinctStudentList = studentList.Distinct(new StudentComparer());

        //Looping through student list

        foreach (var stud in distinctStudentList)

        {

            Console.WriteLine(stud.StudentName);

        }

    }

}

 
After execution we will get the follwing output:

 
execution

If we see the output then we have achieved our goal. But if you see in the implementation, we can't use this Distinct() dynamically because we have tightly associated the comparer and for each property or combination of the properties in the Student class we need to write our custom equality comparer. To avoid that let's use a generic comparer that will do Distinct() with any combination of properties. So here is the modified comparer:
 

public class StudentComparer : IEqualityComparer<Student>

{

    public Func<Student, object> Selector { get; set; }

    public StudentComparer(Func<Student, object> selector)

    {

        Selector = selector;

    }

    public bool Equals(Student x, Student y)

    {

        return Selector(x).Equals(Selector(y));

    }

    public int GetHashCode(Student obj)

    {

            return Selector(obj).GetHashCode();

    }

}


And we can call Distinct() using the following statement:
 

var distinctStudentList = studentList.Distinct(new StudentComparer(x => x.City));

 var distinctStudentList = studentList.Distinct(new StudentComparer(x => new { x.City , x.Country}));


And we will get the corresponding output.