Finding the difference between the two lists

In my current project, I am trying to compare two lists of objects, figuring out whether the same objects were added, deleted, changed, or remained.

I am using IEnumerable.Except for this as follows:

 Dim newOnes = current.Except(previous, equalityComparer).ToList Dim removedOnes = previous.Except(current, equalityComparer).ToList() Dim existingOnes = current.Except(newOnes, equalityComparer).ToList Dim changedOnes = existingOnes.Except(previous, changedComparer).ToList() Dim unchangedOnes = existingOnes.Except(changedOnes, equalityComparer).ToList() 

For this, I have to implement IEqualityComparers.
After finding out whether a pair of objects has changed in the property values ​​(changedOnes), you need to write "changedComparer", which is IEqualityComparer, which checks non-identification fields (for example, member collections).

Since the Except method apparently checks the GetHashCode first and doesn't go to the Equals method if the hashes are equal, my setup is falling apart.

I am currently solving this as follows:

 Public Overloads Function GetHashCode(obj As Family) As Integer Implements IEqualityComparer(Of Family).GetHashCode Dim hashCode As Long = 17 If obj.ClientCode IsNot Nothing Then hashCode = CInt(((hashCode * 397) Xor obj.ClientCode.GetHashCode()) Mod Integer.MaxValue) ' SNIP a bunch more property fields If obj.Members IsNot Nothing Then hashCode = CInt(((hashCode * 397) Xor obj.Members.GetHashCode()) Mod Integer.MaxValue) Return CInt(hashCode Mod Integer.MaxValue) End Function 

Adding a member list hash always returns a different hash, as it validates the instance, not the contents. This works for now, but off course removes all the benefits of having a hash.

UPDATE
What I'm looking for is not the best Equals method, but I questioned my entire methodology (maybe there is something OOTB, I should use a different interface). Otherwise, how can I get a good GetHashcode when my collection of properties needs to be taken into account?

+6
source share
2 answers

I think Enumerable.SequenceEqual should do the trick, since it always uses the default equality IEqualityComparer , without requiring IEqualityComparer implementation. However, a warning that it also checks the comparison of orders.

+1
source

I use the KeyEqualityComparer<T, TKey> , which allows me to specify a key that retrieves a lambda to detect any new or deleted items.

I implemented the ListDifference utility (in C #, sorry), which when using keyExtractor and comparer spits a list of new, deleted, changed and immutable elements. This does the obvious thing, i.e.

 public ListDifference(IEnumerable<T> original, IEnumerable<T> updated, Func<T, object> keyExtractor = null, Func<T, T, bool> comparer = null) { if (keyExtractor == null) keyExtractor = t => t; AddedItems = updated.Difference(original, keyExtractor); RemovedItems = original.Difference(updated, keyExtractor); var matches = from u in updated from o in original where keyExtractor(u).Equals(keyExtractor(o)) select Tuple.Create(o, u); if (comparer == null) { //we are unable to detect changed items ChangedItems = null; UnchangedItems = matches; } else { ChangedItems = matches.Where(t => !comparer(t.Item1, t.Item2)); UnchangedItems = matches.Where(t => comparer(t.Item1, t.Item2)); } } 
+1
source

Source: https://habr.com/ru/post/959174/


All Articles