meJustAndrew
meJustAndrew

Reputation: 6623

Compare two lists of custom objects by a specified method C#

I know questions with same title have been asked before, but this is my case:

I want to compare two lists of custom objects which do not override Equals nor they implement IEqualityComparer but I want to compare them against a static comparison method like:

public class Custom
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
}

public static bool Compare(Custom A, Custom B)
{
    return A.Prop1 == B.Prop1 && A.Prop2 == B.Prop2;
}

Assuming that the lists have the elements in same order:

List<Custom> l1 = new List<Custom> {new Custom { Prop1 = "A", Prop2 = "B"}, new Custom { Prop1 = "A", Prop2 = "B" } };
List<Custom> l2 = new List<Custom> { new Custom { Prop1 = "A", Prop2 = "B" }, new Custom { Prop1 = "A", Prop2 = "b" } };

I am trying to avoid a for like this:

if(l1.Count != l2.Count)return;
for (int i = 0; i < l1.Count; i++)
{
    if(!Compare(l1[i], l2[i]))return;
}
bool comparisonResult = true;

using linq, but I guess I am missing something:

bool comparisonResult = l1.Any(x => l2.Any(y => Compare(x, y)));

This is what have tried, but it keeps returning true when lists are not the same.

Upvotes: 5

Views: 3344

Answers (3)

Henrique Oliveira
Henrique Oliveira

Reputation: 1

Now a days, the easiest way to compare a list of custom classes is by using records instead of classes.

Records automatically provides an implementation of IEquatable<T>, which means you don't have to change Equals and GetHashCode method each time you want to add a new field (or remove).

Example Implementation Using Records

Step 1: Define the record object

public record Custom
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
}

Step 2: Method to compare two instances

public bool AreListsEqual(List<Custom> list1, List<Custom> list2)
{
    return list1.SequenceEqual(list2);
}

Step 3: If the order of object isn't important, sort them by some field before compare

public bool AreListsEqual(List<Custom> list1, List<Custom> list2)
{
     var sortedList1 = list1.OrderBy(x => x.Prop1).ToList();
     var sortedList2 = list2.OrderBy(x => x.Prop1).ToList();
     return sortedList1 .SequenceEqual(sortedList2 );
}

Upvotes: 0

avanek
avanek

Reputation: 1659

If you must use LINQ and don't want to implement an IEqualityComparer for Custom...

Assuming the two lists are in the proper sequence, you can make use of Zip to create a new list with each item side-by-side, kind of like a Tuple. You can then call All on that new list to call your static Compare method:

  List<Custom> l1 = new List<Custom> {new Custom { Prop1 = "A", Prop2 = "B"}, new Custom { Prop1 = "A", Prop2 = "B" } };
  List<Custom> l2 = new List<Custom> { new Custom { Prop1 = "A", Prop2 = "B" }, new Custom { Prop1 = "A", Prop2 = "b" } };

  bool comparisonResult = l1.Zip(l2, (x, y) => new { x, y }).All(z => Compare(z.x, z.y));

Upvotes: 4

Gilad Green
Gilad Green

Reputation: 37271

You can use All

bool comparisonResult = l1.All(x => l2.Any(y => Compare(x, y)));

This will return true only if all the items in l1 match the inner condition - which is that they exist in the l2. This is an easier to read way that applying "not" twice.

This will not solve the case of duplicated items in lists so you can:

  1. Distinct the lists
  2. Do in the inner function a Where and count equals to 1

Upvotes: 2

Related Questions