-1

EDIT:

What I'm trying to do is to find if db.Id is equal to xml.Id and db.SubTitle is equal to xml.SubTitle ....etc.....all my prop

also I did tried

bool result = db.SequenceEqual(xml) it returns false all the time.

ENd EDIT

I did search before I end-up asking for help and I'm not sure what is the best way to approach to my problem.

I have two IList objects and both have exact same property but the data might be different. one object is populating from db and other is reading from xml to compare both source is in sync.

here is my object looks like:

public class EmployeeObject
{
    public Int32 Id { get; set; }
    public string SubTitle { get; set; }
    public string Desc { get; set; }
    public bool Active { get; set; }
    public string ActiveDateTime { get; set; }
}

here is what I have tried:

    IList<EmployeeObject> db = Db.EmployeeRepository.PopulateFromDb();
    IList<EmployeeObject> xml = Xml.EmployeeRepository.PopulateFromXml();

//both object populated with data so far so good....

Time to compare now:

I have tried some thing like this:

   if ((object)xml == null || ((object)db) == null)
       return Object.Equals(xml, db);

   return xml.Equals(db); // returning false all the time

i have checked both object has the exact same data and but still returning false

Nick Kahn
  • 19,652
  • 91
  • 275
  • 406

6 Answers6

7

The Equals method that you are using is going to determine if the two references refer to the same list, not if the contents are the same. You can use SequenceEqual to actually verify that two sequences have the same items in the same order.

Next you'll run into the issue that each item in the list will be compared to see if they refer to the same object, rather than containing the same field values, or the same ID values, as seems to be the what you want here. One option is a custom comparer, but another is to pull out the "identity" object in question:

bool areEqual = db.Select(item => item.id)
    .SequenceEqual(xml.Select(item => item.id));
Servy
  • 202,030
  • 26
  • 332
  • 449
  • how would i go if i have check all my prop? i see you are doing only for Id – Nick Kahn Oct 23 '13 at 22:34
  • @AbuHamzah You could define a custom comparer for the item, or override the Equals and GetHashCode methods of that object. – Servy Oct 23 '13 at 22:35
  • @NickKahn You could try this: define Equals() on the element type (the type of the elements in the collections), then call `db.SequenceEqual(xml)`. – Manfred Jun 21 '20 at 08:06
  • What would you do if order didn't matter and you would consider any sequence the same if the characters were the same, even if in different orders? – James Nov 02 '20 at 01:39
  • @James https://stackoverflow.com/questions/50098/comparing-two-collections-for-equality-irrespective-of-the-order-of-items-in-the – Servy Nov 02 '20 at 16:02
2

IList does not have an Equals method. What you're calling is the standard Object equals which checks whether two variables point to the same object or not.

If you want to check that the lists are semantically equivalent, you will need to check that each object in the list is equivalent. If the EmployeeObject class has an appropriate Equals method, then you can use SequenceEquals to compare the lists.

Steve
  • 7,171
  • 2
  • 30
  • 52
  • EmployeeObject does not have a Equals method, will you show me how should i be going further? and as i said I did try using SequanceEquals but does not work. – Nick Kahn Oct 23 '13 at 22:33
2

You should override Equals and GetHashCode in your class like this:

public class EmployeeObject {
  public Int32 Id { get; set; }
  public string SubTitle { get; set; }
  public string Desc { get; set; }
  public bool Active { get; set; }
  public string ActiveDateTime { get; set; }
  public override bool Equals(object o){
     EmployeeObject e = o as EmployeeObject;
     if(e == null) return false;
     return Id == e.Id && SubTitle == e.SubTitle && Desc == e.Desc 
            && Active == e.Active && ActiveDateTime == e.ActiveDateTime; 
  }
  public override int GetHashCode(){
     return Id.GetHashCode() ^ SubTitle.GetHashCode() ^ Desc.GetHashCode()
            ^ Active.GetHashCode() ^ ActiveDateTime.GetHashCode();             
  }
}

Then use the SequenceEqual method:

return db.OrderBy(e=>e.Id).SequenceEqual(xml.OrderBy(e=>e.Id));
King King
  • 61,710
  • 16
  • 105
  • 130
1

You can implement an IEqualityComparer and use the overload of SequenceEquals that takes an IEqualityComparer. Here is sample code for an IEqualityComparer from msdn:

class BoxEqualityComparer : IEqualityComparer<Box>
{
    public bool Equals(Box b1, Box b2)
    {
        if (b1.Height == b2.Height && b1.Length == b2.Length && b1.Width == b2.Width)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public int GetHashCode(Box bx)
    {
        int hCode = bx.Height ^ bx.Length ^ bx.Width;
        return hCode.GetHashCode();
    }
}

You can then use SequenceEquals like this:

if (db.SequnceEquals(xml), new MyEqualityComparer())
    { /* Logic here */ }

Note that this will only return true if the items also are ordered in the same order in the lists. If appropriate, you can pre-order the items like this:

if (db.OrderBy(item => item.id).SequnceEquals(xml.OrderBy(item => item.id)), new MyEqualityComparer())
    { /* Logic here */ }
lightbricko
  • 2,649
  • 15
  • 21
0

Obviously, the return of return xml.Equals(db); will always be false if you are comparing two different lists.

The only way for this to make sense is for you to actually be more specific about what it means for those two lists to be equal. That is you need to go through the elements in the two lists and ensure that the lists both contain the same items. Even that is ambiguous but assuming that the elements in your provide a proper override for Equals() and GetHashCode() then you can proceed to implement that actual list comparison.

Generally, the most efficient method to compare two lists that don't contain duplicates will be to use a hash set constructed from elements of one of the lists and then iterate through the elements of the second, testing whether each element is found in the hash set.

If the lists contain duplicates your best bet is going to be to sort them both and then walk the lists in tandem ensuring that the elements at each point match up.

Mike Dinescu
  • 54,171
  • 16
  • 118
  • 151
0

You can use SequenceEqual provided you can actually compare instances of EmployeeObject. You probably have to Equals on EmployeeObject:

public override bool Equals(object o)
{
  EmployeeObject obj = o as EmployeeObject;
  if(obj == null) return false;

  // Return true if all the properties match
  return (Id == obj.Id &&
          SubTitle == obj.SubTitle &&
          Desc == obj.Desc &&
          Active == obj.Active &&
          ActiveDateTime == obj.ActiveDateTime);
}

Then you can do:

var same = db.SequenceEqual(xml);

You can also pass in a class that implements IEqualityComparer which instructs SequenceEqual how to compare each instance:

var same = db.SequenceEqual(xml, someComparer);

Another quick way, though not as fast, would be to build two enumerations of the value you want to compare, probably the id property in your case:

var ids1 = db.Select(i => i.Id); // List of all Ids in db
var ids2 = xml.Select(i => i.Id); // List of all Ids in xml
var same = ids1.SequenceEqual(ids2); // Both lists are the same
Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
  • Why are you making the exact same query in both method and query syntax in the same line of code? – Servy Oct 23 '13 at 22:36
  • @Servy - Decided to just break it into 3 lines of code to make it clearer what was going on. It can obviously be simplified into a single line if desired. – Mike Christensen Oct 23 '13 at 22:46