1

I'm sure that my question is similar to many questions asked on StackOverflow. But I think that my problem is a little bit different from the questions asked here.

What I need exactly is to compare two lists of objects with only Id and with the ignorance of order :

List 1 of Person { Id Name }
List 2 of Person { Id Name }

Suppose that I have these two lists:

List 1 { 1 , John } , {2 , Mike } , {3 , Justin }
List 2 { 2 , Mike } , {1 , John } , {3 , Justin }

In this case, the result returned should be true because the two lists are equals ignoring the order.

In another case:

List 1 { 1 , John } , {2 , Mike } , {4 , Justin }
List 2 { 2 , Mike } , {1 , John } , {3 , Justin }

This should returns false .

I've tried Find, FindAll, Except but any of them worked for me. this is the last solution that I've tried:

 foreach(PersonModel d in PersonsList1) {
   var Test = PersonsList2.All(x => x.Id== d.Id);
 }

How can I get this works?

Note: there is no occurrence in the two lists

Thanks.

abdou31
  • 45
  • 1
  • 8

3 Answers3

1

If you don't have any duplicates, and you just want to see whether both lists contain the same set of IDs, then this is a set operation and the easiest solution uses a HashSet<int>:

bool same = list1.Select(x => x.Id).ToHashSet().SetEquals(list2.Select(x => x.Id));

You can optimize by checking the lengths of your two lists first: if they're different lengths, they're obviously different:

bool same = list1.Count == list2.Count &&
    list1.Select(x => x.Id).ToHashSet().SetEquals(list2.Select(x => x.Id));

If you want to get the objects which are different between the two lists, you can use HashSet<T>.SymmetricExceptWith. The problem here is that we now need to be comparing Person objects directly, rather than taking their IDs first, because need those Person objects out of the other side.

Therefore, we'll need to write our own IEqualityComparer:

public class PersonIdComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y) => x.Id == y.Id;
    public int GetHashCode(Person x) => x.Id.GetHashCode();
}

var set = list1.ToHashSet(new PersonIdComparer());
set.SymmetricExceptWith(list2);
// set now contains the differences
canton7
  • 37,633
  • 3
  • 64
  • 77
0

What about:

var list1 = new List<(int Id, string Name)> { (1, "John"), (2, "Mike"), (3, "Justin") };
var list2 = new List<(int Id, string Name)> { (2, "Mike"), (1, "John"), (3, "Justin") };

var list1Ids = list1.OrderBy(item => item.Id).Select(item => item.Id);
var list2Ids = list2.OrderBy(item => item.Id).Select(item => item.Id);

Assert.IsTrue(Enumerable.SequenceEqual(list1Ids, list2Ids)); // IsTrue

Updated after comments from @Charlieface and @canton7.

dbraillon
  • 1,742
  • 2
  • 22
  • 34
0

As previous folks mentioned, there's not enough context in OP. But one of the solutions (and it would spare enumerations on collection compared to previous)

var result = Enumerable.Empty<Person>().Concat(List1).Concat(List2)
            .GroupBy(x => x.Id)
            .Any(x => x.Count() == 1)

It creates new collection safely and looks for groups with only one member, which means where was just one entry in one of the initial collections with provided Id.