Search code examples
c#linqdistinctiequalitycompareriequatable

Make List<Student> Distinctable with IEquatable<Student>


I wanted to make my Class Sortable(By Age) when it stored in List.

I read this : IComparable Vs IComparer and I maked my class Sortable .

public class Student : IComparable<Student>
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }

    public int CompareTo(Student other)
    {
        if (this.Age > other.Age)
        {
            return 1;
        }
        else if (this.Age < other.Age)
        {
            return -1;
        }
        else
        {
            return 0;
        }
    }
}

List students = new List();

// And Filling students

students.Sort();

Now , I want to make my class Distinctable , I mean when I call .Distinct() it remove duplicate students By ID .

I read IEquatable VS IEqualityComparer And same as Sort ( That give no argumants ) I expect to call .Distinct() with no passing argumants.

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

        public bool Equals(Student other)
        {
            if (this.ID == other.ID)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
}

List students = new List();

// And Filling students

students.Distinct();

But when I use this nothing happened . WHY ?

And How can I implement IEquatable and use Distinct() with no passing argumants ?


Solution

  • See what Enumerable.Distinct's docs says:

    The default equality comparer, Default, is used to compare values of the types that implement the IEquatable generic interface. To compare a custom data type, you need to implement this interface and provide your own GetHashCode and Equals methods for the type.

    I don't see that your Student class:

    • ...overrides Object.GetHashCode(...).
    • ...overrides Object.Equals(...)

    In the other hand, Enumerable.Distinct returns:

    ...an unordered sequence that contains no duplicate values. It uses the default equality comparer, Default, to compare values.

    Thus, you need to set the result to a variable:

    var x = enumerable.Distinct();
    

    Consider using a HashSet<T>

    Perhaps you want your collection to contain unique elements. If this is the case, don't store elements in a regular collection to later call Enumerable.Distinct(), but use a HashSet<T> directly.

    Once you've fixed your Student class overriding the whole methods mentioned above, you'll be able to store students as follows:

    HashSet<Student> studentSet = new HashSet<Student();
    studentSet.Add(new Student { ID = 1, Name = "Matías", Age = 32 });
    
    // HashSet<T>.Add returns true if it could add the whole element. 
    // In our case, this if statement will never enter!
    if(studentSet.Add(new Student { ID = 1, Name = "Matías", Age = 32 }))
    {
    }