Last active
May 18, 2021 05:15
-
-
Save NullVoxPopuli/f95baaa48b4e9854dcfe to your computer and use it in GitHub Desktop.
Deep Equality Compare of Nested Dictionaries and Lists
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Imports System.Collections.Generic | |
Namespace AUL | |
Partial Class Utils | |
Private Shared _valueComparer As EqualityComparer(Of Object) = EqualityComparer(Of Object).Default | |
''' <summary> | |
''' | |
''' There is no pre-given implementation of .Equals | |
''' that deeply compares based on value instead of | |
''' reference. The standard .Equals only returns | |
''' true if the two Dictionaries are the same object | |
''' | |
''' </summary> | |
''' <param name="a"></param> | |
''' <param name="b"></param> | |
''' <returns></returns> | |
''' <remarks></remarks> | |
Public Shared Function CollectionsAreEqual( _ | |
ByVal a As Object, _ | |
ByVal b As Object) As Boolean | |
Dim result As Boolean = True | |
If (a.Equals(b)) Then Return True | |
If (a Is Nothing Or b Is Nothing) Then Return True | |
If (Not a.Count.Equals(b.Count)) Then Return False | |
If (Not a.GetType.Equals(b.GetType)) Then Return False | |
' we can assume both types are the same due to the type check above | |
' call the corresponding helper method based on whether this is | |
' a dictionary or a list | |
If (a.GetType.Equals(GetType(Dictionary(Of String, Object)))) Then | |
result = result AndAlso CollectionDictionariesAreEqualHelper(a, b) | |
ElseIf (a.GetType.Equals(GetType(List(Of Object)))) Then | |
result = result AndAlso CollectionListsAreEqualHelper(a, b) | |
Else | |
' Nothing to iterate over, we should have returned before getting here | |
End If | |
Return result | |
End Function | |
Private Shared Function CollectionDictionariesAreEqualHelper(ByVal a As Dictionary(Of String, Object), _ | |
ByVal b As Dictionary(Of String, Object)) As Boolean | |
Dim result As Boolean = True | |
For Each kvp As KeyValuePair(Of String, Object) In a | |
Dim valueA As Object = kvp.Value | |
Dim valueB As Object | |
' if the second dictionary has the key | |
If (Not b.TryGetValue(kvp.Key, valueB)) Then Return False | |
' We don't care what a and b are, but the CollectionsAreEqual | |
' Function should take care of every case of object | |
result = (result And CollectionsAreEqual(valueA, valueB)) | |
' Terminate if this loop caused an inequality | |
If (Not result) Then Return False | |
Next | |
Return result | |
End Function | |
Private Shared Function CollectionListsAreEqualHelper(ByVal a As List(Of Object), _ | |
ByVal b As List(Of Object)) As Boolean | |
Dim result As Boolean = True | |
Dim i As Integer | |
For i = 0 To a.Count - 1 | |
Dim valueA As Object = a(i) | |
Dim valueB As Object = b(i) | |
' We don't care what a and b are, but the CollectionsAreEqual | |
' Function should take care of every case of object | |
result = (result And CollectionsAreEqual(valueA, valueB)) | |
If (Not result) Then Return False | |
Next | |
Return result | |
End Function | |
End Class | |
End Namespace | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Imports System.Text | |
Imports Microsoft.VisualStudio.TestTools.UnitTesting | |
Imports System.Collections.Generic | |
<TestClass()> Public Class CollectionEqualityTest | |
<TestMethod()> Public Sub EmptyCollections() | |
Dim h1 As New Dictionary(Of String, Object) | |
Dim h2 As New Dictionary(Of String, Object) | |
Assert.IsTrue(AUL.Utils.CollectionsAreEqual(h1, h2)) | |
End Sub | |
<TestMethod> Public Sub SmallSameCollections() | |
Dim h1 As New Dictionary(Of String, Object) | |
Dim h2 As New Dictionary(Of String, Object) | |
h1.Add("1", "2") | |
h2.Add("1", "2") | |
Assert.IsTrue(AUL.Utils.CollectionsAreEqual(h1, h2)) | |
End Sub | |
<TestMethod> Public Sub MultipleEntries() | |
Dim h1 As New Dictionary(Of String, Object) | |
Dim h2 As New Dictionary(Of String, Object) | |
h1.Add("1", "2") | |
h2.Add("1", "2") | |
h1.Add("one", "two") | |
h2.Add("one", "two") | |
h1.Add("and 1", "and 2") | |
h2.Add("and 1", "and 2") | |
Assert.IsTrue(AUL.Utils.CollectionsAreEqual(h1, h2)) | |
End Sub | |
<TestMethod> Public Sub NestedHashes() | |
Dim h1 As New Dictionary(Of String, Object) | |
Dim h2 As New Dictionary(Of String, Object) | |
Dim h3 As New Dictionary(Of String, Object) | |
Dim h4 As New Dictionary(Of String, Object) | |
h1.Add("1", "2") | |
h2.Add("1", "2") | |
h1.Add("one", h3) | |
h2.Add("one", h4) | |
Assert.IsTrue(AUL.Utils.CollectionsAreEqual(h1, h2)) | |
End Sub | |
<TestMethod> Public Sub Lists() | |
Dim h1 As New List(Of Object) | |
Dim h2 As New List(Of Object) | |
h1.Add(1) | |
h1.Add(2) | |
h2.Add(1) | |
h2.Add(2) | |
Assert.IsTrue(AUL.Utils.CollectionsAreEqual(h1, h2)) | |
End Sub | |
<TestMethod> Public Sub HashesWithLists() | |
Dim h1 As New Dictionary(Of String, Object) | |
Dim h2 As New Dictionary(Of String, Object) | |
Dim h3 As New List(Of Object) | |
Dim h4 As New List(Of Object) | |
h3.Add(1) | |
h3.Add(2) | |
h4.Add(1) | |
h4.Add(2) | |
h1.Add("1", "2") | |
h2.Add("1", "2") | |
h1.Add("one", h3) | |
h2.Add("one", h4) | |
Assert.IsTrue(AUL.Utils.CollectionsAreEqual(h1, h2)) | |
End Sub | |
<TestMethod> Public Sub DeeplyNestedData() | |
Dim h1 As Dictionary(Of String, Object) = TestData.GenerateGroupData | |
Dim h2 As Dictionary(Of String, Object) = TestData.GenerateGroupData | |
Assert.IsTrue(AUL.Utils.CollectionsAreEqual(h1, h2)) | |
End Sub | |
End Class |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment