I am trying to compare 2 lists of objects for equality, but I want to ignore the key field. How can I do this?
Here is an example:
public class myProduct
{
int ID {get; set;}
int field1 {get; set;}
int field2 {get; set;}
}
<List>myProduct greenProducts = new <List>myProduct();
<List>myProduct purpleProducts = new <List>myProduct();
greenProducts.Add(new myProduct { ID = 1, field1 = 5, field2 = 8});
greenProducts.Add(new myProduct { ID = 2, field1 = 9, field2 = 12});
greenProducts.Add(new myProduct { ID = 3, field1 = 7, field2 = 7});
purpleProducts.Add(new myProduct { ID = 8, field1 = 5, field2 = 8});
purpleProducts.Add(new myProduct { ID = 9, field1 = 9, field2 = 12});
purpleProducts.Add(new myProduct { ID = 10, field1 = 7, field2 = 7});
If you ignore the key field (aka the ID field), these lists are exactly the same.
So I want my code to do something like this:
if (purpleProducts == greenProducts) //I WANT THE ID FIELD IGNORED FOR THE COMPARISON SO RESULT WITH ABOVE DATA WOULD BE TRUE
{
//DO ACTION HERE
}
CodePudding user response:
you can loop through it. Here is a loop that will make sure the number of duplicates are the same.
public class myProduct
{
public int ID { get; set; }
public int field1 { get; set; }
public int field2 { get; set; }
}
List<myProduct> greenProducts = new List<myProduct>();
List<myProduct> purpleProducts = new List<myProduct>();
greenProducts.Add(new myProduct { ID = 1, field1 = 5, field2 = 8 });
greenProducts.Add(new myProduct { ID = 2, field1 = 9, field2 = 12 });
greenProducts.Add(new myProduct { ID = 3, field1 = 7, field2 = 7 });
purpleProducts.Add(new myProduct { ID = 8, field1 = 5, field2 = 8 });
purpleProducts.Add(new myProduct { ID = 9, field1 = 9, field2 = 12 });
purpleProducts.Add(new myProduct { ID = 10, field1 = 7, field2 = 7 });
var areEqual = true;
if (greenProducts.Count() != purpleProducts.Count()) areEqual = false;
if (areEqual)
{
foreach (var item in greenProducts)
{
if(greenProducts.Where(g => g.field1 == item.field1 && g.field2 == item.field2).Count() != purpleProducts.Where(p => p.field1 == item.field1 && p.field2 == item.field2).Count())
{
areEqual = false;
break;
}
}
}
if (areEqual)
{
//DO ACTION HERE
}
CodePudding user response:
So, no duplicates to worry about, elements could be in any order
if(
green.Select(x => new { x.field1, x.field2 })
.ToHashSet()
.SetEquals(purple.Select(x => new { x.field1, x.field2 }))
)
We take your collections and project them to anonymous types of just the fields you want to compare. An anonymous type has built in equality logic based on the data contents of the properties, which saves you from having to override Equals and GetHashCode in your class (which would be another option). By turning one of the collections into a hashset you can then ask it if it equals the other collection. The other collection need not be a hashset.
A similar effect can be achieved with tuple, which also have built in equality checking
if(
green.Select(x => (x.field1, x.field2))
.ToHashSet()
.SetEquals(purple.Select(x => (x.field1, x.field2)))
)
If you override Equals and GetHashCode on your class so that they declare equal purely based on field1 and field2 the code gets simpler:
if(green.ToHashSet().SetEquals(purple))
The overridden methods would look something like:
override bool Equals(object other) => other is MyProduct x && this.field1 == x.field1 && this.field2 == x.field2;
override int GetHashCode() => HashCode.Combine(field1, field2);
If you make your collections HashSet (with the overrides done above too) instead of List then they automatically dedupe themselves and the code is simply
if(green.SetEquals(purple))
CodePudding user response:
green.Zip(purple, (l,r)=>(l.field1 == r.field1) && (l.field2 == r.field2)).All(x=>x);
