Page 1 of 1

LINQ by Example 3: Methods Using IEqualityComparer

#1 andrewsw  Icon User is online

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3352
  • View blog
  • Posts: 11,346
  • Joined: 12-December 12

Posted 25 August 2014 - 11:24 AM

LINQ by Example 1: Enumerable Methods A-L
LINQ by Example 2: Enumerable Methods M-Z

The following methods have overloads than can use an IEqualityComparer:

Contains, Distinct, Except, GroupBy x4, GroupJoin, Intersect,
Join, SequenceEqual, ToDictionary x2, ToLookup x2, Union


(x4 means that GroupBy has four overloads that take a comparer.)

I provide examples for Contains, Distinct, Except, Intersect, SequenceEquals and Union.

IEqualityComparer<T> Interface

MSDN said:

Defines methods to support the comparison of objects for equality.


We need two classes to demonstrate the use of a comparer. You can add these to the code template (from the first tutorial) as the names do not conflict with any of the earlier examples. Class Department provides a very simple object and DepartmentComparer allows us to compare two departments.
    public class Department {
        public string Code { get; set; }
        public string Name { get; set; }
    }

    public class DepartmentComparer : IEqualityComparer<Department> {

        // equal if their Codes are equal
        public bool Equals(Department x, Department y) {
            // reference the same objects?
            if (Object.ReferenceEquals(x, y)) return true;

            // is either null?
            if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
                return false;

            return x.Code == y.Code;
        }

        public int GetHashCode(Department dept) {
            // If Equals() returns true for a pair of objects 
            // then GetHashCode() must return the same value for these objects.

            // if null default to 0
            if (Object.ReferenceEquals(dept, null)) return 0;

            return dept.Code.GetHashCode();
        }
    }


The Equals method simply returns true or false if we consider two departments to be the same. GetHashCode() is necessary to ensure that two departments that are considered the same also have the same hash-code. String.GetHashCode Method.

The following page provides a little more information:

Implementing IEqualityComparer<T>

You might consider that two companies are being merged, but they have different titles for their various departments. One company would be considered to provide the main department-details and the other company details need to be incorporated.

(In reality, a conformance table would probably be created that cross-matches the department details, and the database records of the two companies might be merged by referencing this table.)

In the main code (of our template) we can now create collections of departments:
    Department[] departments = { new Department { Code = "MK", Name = "Marketing" },
                                   new Department { Code = "SA", Name = "Sales" },
                                   new Department { Code = "AC", Name = "Accounts" },
                                   new Department { Code = "AC", Name = "Accounting" },
                                   new Department { Code = "HR", Name = "Human Resources" },
                                   new Department { Code = "HR", Name = "Human Res." }};

    Department[] departments2 = { new Department { Code = "MK", Name = "Marketing" },
                                   new Department { Code = "SA", Name = "Sales" },
                                   new Department { Code = "IT", Name = "Information Technology" },
                                   new Department { Code = "HR", Name = "Human Rsc" }};

    Department[] departments3 = { new Department { Code = "MK", Name = "Marketing" },
                                   new Department { Code = "IT", Name = "Information Tech." },
                                   new Department { Code = "SA", Name = "Sales" },
                                   new Department { Code = "HR", Name = "Human Resources" }};


Contains
    bool deptContains = departments.Contains(
        new Department { Code = "AC", Name = "Accts." }, new DepartmentComparer());

    Console.WriteLine("It {0} contained.", deptContains ? "is" : "isn't");
    // It is contained.


Distinct
    IEnumerable<Department> deptDistinct = departments.Distinct(new DepartmentComparer());

    foreach (Department dept in deptDistinct) {
        Console.WriteLine("{0} {1}", dept.Code, dept.Name);
        //Console.WriteLine(dept.Code.GetHashCode());   // for testing
    }


Departments with Code "AC" are considered to be the same so, when displaying the Name, which name appears? The first one: "Accounts".

Except
    IEnumerable<Department> deptExcept = departments.Except(departments2, 
        new DepartmentComparer());

    foreach (Department dept in deptExcept) {
        Console.WriteLine("{0} {1}", dept.Code, dept.Name);
    }
    // departments not in departments2: AC, Accounts.


Intersect
    Console.WriteLine("Intersecting departments:");

    IEnumerable<Department> deptIntersect = departments.Intersect(departments2,
        new DepartmentComparer());

    foreach (Department dept in deptIntersect) {
        Console.WriteLine("{0} {1}", dept.Code, dept.Name);
    }
    // MK Marketing, SA Sales, HR Human Resources


SequenceEqual
    bool deptEquals = departments2.SequenceEqual(departments3, new DepartmentComparer());

    Console.WriteLine("They are{0}the same.", deptEquals ? " " : " not ");
    // They are not the same. Change them to have the same order and they
    // will be the same.


Union
    Console.WriteLine("Union of departments and departments 2:");

    IEnumerable<Department> deptUnion = departments.Union(departments2,
        new DepartmentComparer());

    foreach (Department dept in deptUnion) {
        Console.WriteLine("{0} {1}", dept.Code, dept.Name);
    }
    // MK SA AC HR IT
    // (each only appears once, with AC displaying as "Accounts"
    // and HR as "Human Resources")


Enumerable Methods A-L
Enumerable Methods M-Z

This post has been edited by andrewsw: 25 August 2014 - 02:45 PM


Is This A Good Question/Topic? 1
  • +

Page 1 of 1