Solved

Compare two  collection of objects in c#

Posted on 2014-09-25
9
324 Views
Last Modified: 2014-10-07
I am writing unit tests and have a below Employee class .Basically an employee can have single or more than one address.I want to compare two Employee objects that will return true or false.How can I compare these two objects in the EmployeeEqualityComparer class?

//Employee
public class Employee{

public collection<AddressList> AddressDetails{get;set;}

public string Name{get;set;}

public int Age {get;set;}
}

public class AddressList
{

public string Street{get;set;}
public string Lane{get;set;}
public string City{get;set;}

}
// Implemented IEqualityComparer interface
public class EmployeeEqualityComparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
    
   
}

public int GetHashCode(Employee obj)
{
    return obj.GetHashCode;
}

Open in new window

0
Comment
Question by:ksd123
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 12

Expert Comment

by:Ramkisan Jagtap
ID: 40345393
public bool Equals(Employee x, Employee y)
{
    return  ((object)x).Equals((object)y);   
}

Open in new window

0
 

Author Comment

by:ksd123
ID: 40346617
I am getting false even though both objects contain same items .
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 500 total points
ID: 40347251
That's because object.Equals compares references, not values. Since you have two different objects in memory, Equals returns false. You need to determine what aspects of your class would make two instances "equal". Say, for example, that two instances are equal if they both have the same value for the Name property. You could adjust your equality comparer in a manner such as this:

public bool Equals(Employee x, Employee y)
{
    return string.Equals(x.Name, y.Name);
}

Open in new window


If you determine that additional properties are needed for equality, then you can simply add those in to your condition:

e.g.

public bool Equals(Employee x, Employee y)
{
    return string.Equals(x.Name, y.Name) &&
           x.Age == y.Age;
}

Open in new window


For your EqualityComparer, you'll probably want to change the name to something that indicates how the comparison(s) work. For my first example, the one that compares names, I would name the comparer as:

public class EmployeeByNameEqualityComparer : IEqualityComparer<Employee>
{
    public bool Equals(Employee x, Employee y)
    {
        return string.Equals(x.Name, y.Name);
    }
}

Open in new window


With this name, it's clear to someone coming behind me how the comparison works, even without inspecting the comparer's definition. I can also have different comparers that compare different properties, so should I ever run into a situation where I need to switch up how two things are considered equal, I can simply swap out the comparer I use.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:ksd123
ID: 40348552
thank you so much for your explanation.Actually I am writing unit tests and want compare 2 employee objects(expected,actual).Here is my data for employee object(actual) check below code and similar data I will have employee object(expected).Basically an employee can have multiple addresses and am confused how can I set properties and compare two objects.In the  EmployeeByNameEqualityComparer class how can I compare these 2 objects using linq or normal way?

//Fake data
var Emloyeefakeresult=new Employee
{

Name="abc";
Age=32;

AddressDetails=new List<AddressList>(){new AddressList()

          {
		Street=street1;
                Lane=lane1;
                City=NY;
          },
	  {
		Street=street1;
                Lane=lane1;
                City=NY;
          }

}

};

Open in new window

0
 
LVL 63

Expert Comment

by:Fernando Soto
ID: 40348601
Hi ksd123;

You need to know out of all the properties in the Employee class which properties you want to match against another Employee for the two to be considered as equal. For example in your last post you have an Name and Age property as well as a collection of AddressList. So will two Employee object be equal on just a Employee Name or Employee Name and Age or Employee Name and Age and one member of the AddressList or do ALL properties and ALL collection members must match for two Employee objects are to be considered as equal.
0
 

Author Comment

by:ksd123
ID: 40348632
Hi,
ALL properties and ALL collection members must match for two Employee objects are to be considered as equal
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 40348666
You'll probably want to implement a comparer for the addresses also:

// Implemented IEqualityComparer interface
public class AddressByAllEqualityComparer : IEqualityComparer<AddressList>
{
    public bool Equals(AddressList x, AddressList y)
    {
        return string.Equals(x.City, y.City) &&
                string.Equals(x.Lane, y.Lane) &&
                string.Equals(x.Street, y.Street);
    }

    public int GetHashCode(AddressList obj)
    {
        return obj.GetHashCode();
    }
}

Open in new window


...and you can simply add the remaining properties to the employee comparer:

// Implemented IEqualityComparer interface
public class EmployeeByAllEqualityComparer : IEqualityComparer<Employee>
{
    public bool Equals(Employee x, Employee y)
    {
        return x.Age == y.Age &&
                string.Equals(x.Name, y.Name) &&
                Enumerable.SequenceEqual(x.AddressDetails, y.AddressDetails, new AddressByAllEqualityComparer());
    }

    public int GetHashCode(Employee obj)
    {
        return obj.GetHashCode();
    }
}

Open in new window


Putting it all together:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace _28525773
{
    class Program
    {
        static void Main(string[] args)
        {
            Employee e1 = new Employee() { Age = 10, Name = "Steve", AddressDetails = new Collection<AddressList>() { new AddressList() { City = "Toledo", Lane = "123", Street = "Anystreet" } } };
            Employee e2 = new Employee() { Age = 10, Name = "Fred", AddressDetails = new Collection<AddressList>() { new AddressList() { City = "Toledo", Lane = "123", Street = "Anystreet" } } };
            Employee e3 = new Employee() { Age = 10, Name = "Steve", AddressDetails = new Collection<AddressList>() { new AddressList() { City = "Los Angeles", Lane = "123", Street = "Anystreet" } } };
            Employee e4 = new Employee() { Age = 10, Name = "Steve", AddressDetails = new Collection<AddressList>() { new AddressList() { City = "Toledo", Lane = "123", Street = "Anystreet" } } };
            EmployeeByAllEqualityComparer comparer = new EmployeeByAllEqualityComparer();

            Console.WriteLine("e1 == e2? {0}", comparer.Equals(e1, e2));
            Console.WriteLine("e1 == e3? {0}", comparer.Equals(e1, e3));
            Console.WriteLine("e1 == e4? {0}", comparer.Equals(e1, e4));
            Console.WriteLine("e2 == e3? {0}", comparer.Equals(e2, e3));
            Console.WriteLine("e2 == e4? {0}", comparer.Equals(e2, e4));
            Console.WriteLine("e3 == e4? {0}", comparer.Equals(e3, e4));
            Console.ReadLine();
        }
    }

    public class Employee
    {

        public Collection<AddressList> AddressDetails { get; set; }

        public string Name { get; set; }

        public int Age { get; set; }
    }

    public class AddressList
    {

        public string Street { get; set; }
        public string Lane { get; set; }
        public string City { get; set; }

    }

    // Implemented IEqualityComparer interface
    public class EmployeeByAllEqualityComparer : IEqualityComparer<Employee>
    {
        public bool Equals(Employee x, Employee y)
        {
            return x.Age == y.Age &&
                    string.Equals(x.Name, y.Name) &&
                    Enumerable.SequenceEqual(x.AddressDetails, y.AddressDetails, new AddressByAllEqualityComparer());
        }

        public int GetHashCode(Employee obj)
        {
            return obj.GetHashCode();
        }
    }

    // Implemented IEqualityComparer interface
    public class AddressByAllEqualityComparer : IEqualityComparer<AddressList>
    {
        public bool Equals(AddressList x, AddressList y)
        {
            return string.Equals(x.City, y.City) &&
                    string.Equals(x.Lane, y.Lane) &&
                    string.Equals(x.Street, y.Street);
        }

        public int GetHashCode(AddressList obj)
        {
            return obj.GetHashCode();
        }
    }
}

Open in new window

0
 

Author Comment

by:ksd123
ID: 40348699
Thank you.Just want to double check  will the above code work if I have multiple addresses for a single employee ? ie

var Emloyeefakeresult=new Employee
{

Name="abc";
Age=32;

AddressDetails=new List<AddressList>(){new AddressList()

          {
		Street=street1;
                Lane=lane1;
                City=NY;
          },
	  {
		Street=street2;
                Lane=lane2;
                City=NJ;
          },

       {
		Street=street3;
                Lane=lane3;
                City=MI;
          },

}

};

Open in new window

0
 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 500 total points
ID: 40348705
Yes. I haven't looked at the internals, but I believe one of the things that SequenceEqual does is compare the length of the two collections. If the lengths are different, then the two collections cannot be equal.

static void Main(string[] args)
{
    Employee e1 = new Employee() { Age = 10, Name = "Steve", AddressDetails = new Collection<AddressList>() { new AddressList() { City = "Toledo", Lane = "123", Street = "Anystreet" } } };
    Employee e2 = new Employee() { Age = 10, Name = "Fred", AddressDetails = new Collection<AddressList>() { new AddressList() { City = "Toledo", Lane = "123", Street = "Anystreet" } } };
    Employee e3 = new Employee() { Age = 10, Name = "Steve", AddressDetails = new Collection<AddressList>() { new AddressList() { City = "Los Angeles", Lane = "123", Street = "Anystreet" } } };
    Employee e4 = new Employee() { Age = 10, Name = "Steve", AddressDetails = new Collection<AddressList>() { new AddressList() { City = "Toledo", Lane = "123", Street = "Anystreet" }, new AddressList() { City = "London", Lane = "123", Street = "Anystreet" } } };
    EmployeeByAllEqualityComparer comparer = new EmployeeByAllEqualityComparer();

    Console.WriteLine("e1 == e2? {0}", comparer.Equals(e1, e2));
    Console.WriteLine("e1 == e3? {0}", comparer.Equals(e1, e3));
    Console.WriteLine("e1 == e4? {0}", comparer.Equals(e1, e4));
    Console.WriteLine("e2 == e3? {0}", comparer.Equals(e2, e3));
    Console.WriteLine("e2 == e4? {0}", comparer.Equals(e2, e4));
    Console.WriteLine("e3 == e4? {0}", comparer.Equals(e3, e4));
    Console.ReadLine();
}

Open in new window

0

Featured Post

Space-Age Communications Transitions to DevOps

ViaSat, a global provider of satellite and wireless communications, securely connects businesses, governments, and organizations to the Internet. Learn how ViaSat’s Network Solutions Engineer, drove the transition from a traditional network support to a DevOps-centric model.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
Email security requires an ever evolving service that stays up to date with counter-evolving threats. The Email Laundry perform Research and Development to ensure their email security service evolves faster than cyber criminals. We apply our Threat…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question