1

Suppose you have two C# lists sales and salesbackup, and you want to get a new list that shows records that exist in both.

These lists were created by reading data from csv files using Csvhelper.

How come this doesnt work?

 foreach (var sale in sales)
        {
            if (salesBackup.Contains(sale))
                dups.Add(sale);
        }

Neither this..

 var dups = sales.Where(x => salesBackup.Contains(x));

Yet this does work ..

 foreach (var sale in sales)
        {
            foreach (var saleBackup in salesBackup)
            {
                if (saleBackup.FirstName == sale.FirstName &&
                    saleBackup.LastName == sale.LastName &&
                    saleBackup.City == sale.City &&
                    saleBackup.Item == sale.Item &&
                    saleBackup.Quantity == sale.Quantity &&
                    saleBackup.Date == sale.Date &&
                    saleBackup.ItemPrice == sale.ItemPrice)
                    dups.Add(saleBackup);
            }
        }

The last solution is pretty clunky.. :( I think Contains uses reference equality so it doesnt work despite the values being the same on all the fields.

LukePerrin
  • 235
  • 5
  • 17
  • For `Contains` to work you'd need to override `Equals` and `GetHashCode` on the class in your lists to do value equality. By default classes have reference equality. – juharr Feb 24 '21 at 14:08
  • 2
    If you implement IEquatable you can [use LINQ Intersect](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.intersect?view=net-5.0) – Crowcoder Feb 24 '21 at 14:08
  • Also see this answer: https://stackoverflow.com/a/29146553/1220550 – Peter B Feb 24 '21 at 14:09
  • An instance of a `Sale` object does not necessarily equal a different instance with identical attributes. One such difference is their location in memory, and unless you have provided your own code for `Equals` this difference is enough to cause the two instances to be considered unequal. – h0r53 Feb 24 '21 at 14:09

1 Answers1

3

Override Equals and GetHashCode in your Sale class and then use Intersect method from LINQ:

List<Sale> existInBoth = sales.Intersect(salesDuplicate).ToList();

You can also provide you own comparer to it, so you don't have to override Equals.

maxc137
  • 2,291
  • 3
  • 20
  • 32
  • When you override IEqualityComparer you still have to manually code it to compare all the fields as is on msdn like this.. still pretty tedious if you have 50 fields for example. //Check whether the products' properties are equal. return x.Code == y.Code && x.Name == y.Name; – LukePerrin Mar 03 '21 at 17:52
  • You can define your class as record. This way Equals will be implemented for you – maxc137 Mar 03 '21 at 19:32