Resolved using string() as dictionary key

rsmith1302

New member
Joined
Jul 25, 2023
Messages
4
Programming Experience
10+
If I use an array of strings as a dictionary key, I can't retrieve by key later on. In the following code, why does the second ContainsKey return false?
Dim dict As New Dictionary(Of String(), Integer)
Dim key1 As String() = {"c", "d"}
Dim key2 As String() = {"c", "d"}
dict.Add(key1, 0)
Debug.Print(dict.ContainsKey(key1)) ' returns True
Debug.Print(dict.ContainsKey(key2)) ' returns False

And how do I put my code sample in one of those nicely formatted blocks in this post?
 
Last edited:
Solution
If you use a reference type, i.e. a class, as the key then retrieving by key will use reference equality, not value equality. That means that it will only be recognised as the same array if it is actually the same array, not a different array containing equal elements. If you want to be able to match keys on value rather than reference then you will have to provide a custom equality comparer.

The Dictionary(Of TKey, TValue) class has a constructor that accepts an object of type IEqualityComparer(Of TKey) for that purpose. You can define your own class that implements IEqualityComparer(Of String()) and compares two arrays for equality based on their elements in whatever way you want. That may or may not include...
If you use a reference type, i.e. a class, as the key then retrieving by key will use reference equality, not value equality. That means that it will only be recognised as the same array if it is actually the same array, not a different array containing equal elements. If you want to be able to match keys on value rather than reference then you will have to provide a custom equality comparer.

The Dictionary(Of TKey, TValue) class has a constructor that accepts an object of type IEqualityComparer(Of TKey) for that purpose. You can define your own class that implements IEqualityComparer(Of String()) and compares two arrays for equality based on their elements in whatever way you want. That may or may not include the order of the elements. The implementation of the comparison is completely up to you. You can then pass an instance of that class to the dictionary constructor. You should do some reading on that interface and have a go at implementing it. If you have issues, you can post back with specific questions.
 
Solution
how do I put my code sample in one of those nicely formatted blocks in this post?

You typed your post into a text editor that works like any other text editor. It has a toolbar at the top with buttons for formatting the text. When you hover over those buttons, a tooltip pops up to indicate what that button does. This is just like Microsoft Word or WordPad or any other WYSIWYG text editor you've ever used.
 
If you use a reference type, i.e. a class, as the key then retrieving by key will use reference equality, not value equality. That means that it will only be recognised as the same array if it is actually the same array, not a different array containing equal elements. If you want to be able to match keys on value rather than reference then you will have to provide a custom equality comparer.

The Dictionary(Of TKey, TValue) class has a constructor that accepts an object of type IEqualityComparer(Of TKey) for that purpose. You can define your own class that implements IEqualityComparer(Of String()) and compares two arrays for equality based on their elements in whatever way you want. That may or may not include the order of the elements. The implementation of the comparison is completely up to you. You can then pass an instance of that class to the dictionary constructor. You should do some reading on that interface and have a go at implementing it. If you have issues, you can post back with specific questions.

Thank you - that was a very clear explanation. Time to learn something new!
 
You typed your post into a text editor that works like any other text editor. It has a toolbar at the top with buttons for formatting the text. When you hover over those buttons, a tooltip pops up to indicate what that button does. This is just like Microsoft Word or WordPad or any other WYSIWYG text editor you've ever used.

Thank you - that was a very clear explanation. Time to learn something new!

This seems to work. I swiped the most common solution and made a change because VB doesn't support unchecked. It went through all my data without an overflow. Not sure if a collision would have thrown an exception, but inspection of the results indicates that there weren't any collisions. Thanks again!
Public Class ArrayEqualityComparer
Implements IEqualityComparer(Of String())
Public Overloads Function Equals(x As String(), y As String()) As Boolean Implements IEqualityComparer(Of String()).Equals
Return x.SequenceEqual
End Function

Public Overloads Function GetHashCode(obj As String()) As Integer Implements IEqualityComparer(Of String()).GetHashCode
Dim hash As Long = 17
For Each s In obj
hash = hash And Int32.MaxValue
hash = hash * 23 + If(s IsNot Nothing, s.GetHashCode(), 0)
Next
Return CInt(hash And Int32.MaxValue)
End Function
End Class
 
Back
Top