-1

I have 2 lists of ManualReadTag objects: _manualReadTagList and mrt. The entries in mrt are a subset of _manualReadTagList. I need to get every entry from _manualReadTagList that is "NOT" present in the mrt. So this is how I did it:

IEnumerable<ManualReadTag> difference = _manualReadTagList.Except(mrt).ToList();

But this is not working. I get all the records in the _manualReadTagList and not just whatever is not in the mrt. Below is how I fill the mrt

var mrt = (from ManualReadTag row in ViewingGridFromComparison.ItemsSource
                select new ManualReadTag
                {
                    Plaza = Convert.ToInt16(row.Plaza),
                    Lane = Convert.ToInt16(row.Lane),
                    Trxn_DTime = Convert.ToDateTime(row.Trxn_DTime),
                    Tag_Number = row.Tag_Number
                }).ToList();

IEnumerable<ManualReadTag> difference = _manualReadTagList.Except(mrt).ToList();
ViewingGrid.ItemsSource = difference;

Can you please show me how to do this correctly. Thank you.

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
Ibanez1408
  • 4,550
  • 10
  • 59
  • 110
  • 1
    Have you overriden `Equals` and `GetHashCode` in `ManualReadTag`? – Enigmativity Aug 01 '19 at 04:39
  • Am looking at it as of the moment. It's kinda hard to understand. – Ibanez1408 Aug 01 '19 at 04:41
  • *Whatever is in the _manualReadTagList is also "IN" the mrt but I need to get whatever is in the _manualReadTagList that is "NOT" in the mrt* - this is a contradiction. If you have an _manualReadTagList of 1,2,3,4 and an mrt of 1,2,3,4,5,6 then the first premise *"whatever is in the _manualReadTagList is also in the mrt"* is true, so _manualReadTagList is always a subset of mrt and _manualReadTagList.Except(mrt) is always an empty set – Caius Jard Aug 01 '19 at 04:48
  • @CaiusJard You understood it wrong _manualReadTagList has 1,2,3,4,5,6 and mrt has 2,4 so I should just get 1,3,5,6 – Ibanez1408 Aug 01 '19 at 04:50
  • @Enigmativity I have seen the sample for the custom equality operator. But this is only for strings. What if it's the whole class itself? – Ibanez1408 Aug 01 '19 at 04:52
  • @ibanez in that case your statement *"Whatever is in the _manualReadTagList is also "IN" the mrt"* is FALSE. I think what you mean to say is *"Whatever is in the mrt is also "IN" the _manualReadTagList"* (mrt is a subset of _manualReadTagList) – Caius Jard Aug 01 '19 at 04:55
  • 1
    How do you test if two ManualReadTags are equal? Which of their properties have to be the same for them to be considered identical? – Caius Jard Aug 01 '19 at 04:58
  • I got it. Thank you Enigmativity. – Ibanez1408 Aug 01 '19 at 05:04
  • The [docs](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.except?view=netframework-4.8) provide examples for either overriding Equals _or_ using a Comparer. – H H Aug 01 '19 at 05:04

2 Answers2

1

The problem, if you haven't overridden Equals etc, is that in creating mrt you've created new objects by copying data items out of your old objects. This means the default provisions of Equals and GetHashCode, which are based on the memory address of your ManualReadTag objects, are different and the objects are not considered equal:

ManualReadTag a = new ManualReadTag(){ SomeProperty = 123 };
ManualReadTag b = new ManualReadTag(){ SomeProperty = a.SomeProperty };
ManualReadTag c = a;

a.Equals(b) //false even though they have identical property values, memory addresses are different
a.Equals(c); //true

You need to either need to reuse the same objects so that memory address based equality assertion is true:

//only works if ItemsSource was made from _manualReadTagList
_manualReadTagList.Except( ViewingGridFromComparison.ItemsSource)

Or you need to override Equals and GetHashCode on ManualReadTag (for best performance Except will build a hash set from the mrt then iterate the _mnualReadTagList hashing everything in it and looking it up in the hashset created from mrt. It thus needs to be able to calculate the hash of a ManualReadTag and then, because it is theoretically possible to have two different objects have the same hashcode, use Equals to verify absolutely whether they are the same or not should the hashcodes turn out equal)

Or you need to create your own IEqualityComparer class (see the documentation for an example: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.except - this code example could also be used as a base to override Equals and GetHashCode on ManualReadTag)

Or you need to ditch Except and roll your own; turn mrt into a hashset or dictionary (something that has a fast lookup) based on what properties you consider make two ManualReadTag instances the same, and do what Except does by iterating over _manualReadTagList checking every element for being in mrt - Michal did something like this, though that LINQ solution probably uses nested loops and could have poor performance if the mrt list is large

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
0

Well, you somehow know how to compare two classes, you mentioned:

You understood it wrong _manualReadTagList has 1,2,3,4,5,6 and mrt has 2,4 so I should just get 1,3,5,6

Where are these numbers coming from??? I guess it is the field Tag_Number in ManualReadTag class (if it's different, just replace the field in the code below and it'll work). So you need following code:

_manualReadTagList
  .Where(m => !mrt.Select(i => i.Tag_Number).Contains(m.Tag_Number))
  .ToList();

Other way would be to override Equals method in ManualReadTag to check equality of instances based on particular field (I assume Tag_Number).

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
  • @CaiusJard That's why they should be overriden. Otherwise, code I gave is the way to go :) – Michał Turczyn Aug 01 '19 at 05:10
  • The question was how to use Except not Where. Even so you solved the problem, you didn't answare the question. – Artur Aug 01 '19 at 05:20
  • @michal I accidentally started writing my answer in your comment box (on a cellphone the two boxes are very similar) and submitted it on the first new line , it wasn't intended to be a comment on your answer (sorry) – Caius Jard Aug 01 '19 at 05:36
  • @CaiusJard No worries :) comment was accurate though :) – Michał Turczyn Aug 01 '19 at 05:37