4

How to compare two List<MyObject1> with List<MyObject2>? So if one the Value has different value it should be possible to check it.

(I know we can use foreach... But I'd like LINQ solution/)

Thank you!

public sealed class MyObject1
{
    public string Name { get; set; }

    public string Value { set; get; }

    public Guid ID { get; set; }
}

public sealed class MyObject2
{
    public string Name { get; set; }

    public string Value { set; get; }

    public Guid ID { get; set; }
}
NoWar
  • 36,338
  • 80
  • 323
  • 498

4 Answers4

7

The accepted answer of this SO question suggests using Enumerable.SequenceEqual, documented here.

The method takes two IEnumerables and an IEqualityComparer. It iterates over both your enumerables in parallel and checks equality element by element using the comparer you provide.

In the IEqualityComparer implementation, you may want to compare MyObject instances by their Id properties.

If there really are two object types, you could do something like MyList1.Select(new MyObject2 {/*mapping goes here*/})or try using AutoMapper

Community
  • 1
  • 1
Călin Darie
  • 5,937
  • 1
  • 18
  • 13
2

Your classes are the same, so I believe what you want to do is to compare two lists of Objects of type MyObject:

public class MyObject
{
    public string Name { get; set; }

    public string Value { set; get; }

    public Guid ID { get; set; }
}

I find the easiest way to do this, without having to write a separate IEqualityComparer, is to have the MyObject class implement the IComparable interface. This is explained in detail halfway down this page, but this is what your class would look like after implementing the interface:

public class MyObject :  IEquatable <MyObject >
{
    public string Name { get; set; }

    public string Value { set; get; }

    public Guid ID { get; set; }

    public bool Equals(MyObject other)
    {

    //Check whether the compared object is null. 
    if (Object.ReferenceEquals(other, null)) return false;

    //Check whether the compared object references the same data. 
    if (Object.ReferenceEquals(this, other)) return true;

    //Check whether the objects properties are equal. 
    return Name.Equals(other.Name) && Value.Equals(other.Value) && ID.Equals(other.ID);
    }

    public override int GetHashCode()
    {

    //Get hash code for the Name field if it is not null. 
    int hashName = Name == null ? 0 : Name.GetHashCode();

    //Get hash code for the Value field. 
    int hashCode = Value == null ? 0 : Value .GetHashCode();

    //Get hash code for the IDfield. 
    int hashID =  ID.GetHashCode();

    //Calculate the hash code for the entire object. 
    return hashName  ^ hashCode ^ hashId;
    }
}

Once your class has the Equals() and GetHashCode() methods, the LINQ Except() method will automatically work:

List<MyObject> objects1 = { new MyObject{ Name = "apple", Value= "fruit", ID= 9 }, 
                           new MyObject{ Name = "orange", Value= "fruit", ID= 4 },
                            new MyObject{ Name = "lemon", Value= "fruit", ID= 12 } };

List<MyObject> objects2 = { new MyObject { Name = "apple", Value= "fruit", ID= 9 } };

List<MyObject> comparison = objects1.Except(objects2);

comparison now has orange and lemon, but not apple. I like this solution because of how legible the code is in the last line.

Alex Fairchild
  • 1,025
  • 11
  • 11
2

If you don't want to (or can't) implement your own IEqualityComparer, you could zip and compare fields:

list1.Count == list2.Count 
&& list1
    .Zip(list2, (i1,i2) => new{i1,i2})
    .All(x =>    x.i1.Name  == x.i2.Name
              && x.i1.Value == x.i2.Value
              && x.i1.ID    == x.i2.ID)
spender
  • 117,338
  • 33
  • 229
  • 351
  • the whole idea with ***rer is when you can't edit the class - so you use other class. your sentence is not logical `(or can't) implement your own IEqualityComparer` – Royi Namir Mar 08 '12 at 13:05
  • How about `list1.Zip(list2, (i1, i2) => i1.Name = i2.Name && i1.Value == i2.Value && i1.ID == i2.ID).All()`? – Gabe Mar 08 '12 at 13:07
2
public class myComparer: IEqualityComparer  
{
   public new bool Equals(object x, object y)
   {
      if (x is string )
         return  x ==   y;
      else if (x is Guid ) // maybe you want them to be equal if last char is equal. so you can do it here.
         return   x ==   y;
      else
         return EqualityComparer<object>.Default.Equals(x, y);
   }

   public int GetHashCode(object obj)
   {
      return EqualityComparer<object>.Default.GetHashCode(obj);
   }
}

now

List<MyObject1 > lst1 = new MyObject1 <MyObject1 >(); 
//add items here...

List<MyObject2 > lst2 = new MyObject1 <MyObject2 >(); 
//add items here...

you can equate 2 ways :

IStructuralEquatable equ = lst1 ;

  Console.WriteLine(equ.Equals(lst2 , EqualityComparer<object>.Default));

   or

   Console.WriteLine(equ.Equals(lst2 , new myComparer()));
Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • What do mean t1, t2 in your sample? Could you explain it please? – NoWar Mar 08 '12 at 12:59
  • IMO, this is not a good solution. The type testing makes it expensive, and shoehorning everything to object so that you can use IEqualityComparer is too tricksy by half. – spender Mar 08 '12 at 12:59
  • @spender as long they arent in inheritance mode - you dont have any option. if they'd have a inheritance relationship - we could do something which is type safe. but the OP didnt mentiond it. p.s. look at MSDN sample - exactly as myne : http://msdn.microsoft.com/en-us/library/system.collections.istructuralequatable.aspx they used TUPLES. – Royi Namir Mar 08 '12 at 13:02
  • OK, fair enough. DV removed. Still doesn't look all that nice to me. – spender Mar 08 '12 at 13:04