6

Scripting.Dictionary likes to add values for no reason, when you look a value up! Demonstrated with a 30 second example:

Create a new worksheet, and fill in A1:A4 = {1,2,3,4}

Insert a new vba module and add this code

Public Sub test()

    Dim rowIndex As Integer
    '
    Dim dict As Scripting.Dictionary
    Set dict = New Scripting.Dictionary

    For rowIndex = 1 To 4

        dict.Add Trim(Sheet1.Cells(rowIndex, 1).Value), rowIndex

        Dim notEvenAddingSoWhyAreYouAdding As Variant
        notEvenAddingSoWhyAreYouAdding = dict(Sheet1.Cells(rowIndex, 1).Value)

    Next rowIndex

End Sub

Put a breakpoint on Next rowIndex

Run the sub and inspect the value of dict. It now has two values, "1" and 1, as you can see in the image below:

enter image description here

What. The. Hell?!

I realise I have the Trim(...) function in the dict.Add() line, which means there are two distinct keys in use, but why is it adding an extra value when it does a lookup?! That makes no sense whatsoever - now dict.Count would not give the value I would expect.

CallumDA
  • 12,025
  • 6
  • 30
  • 52
  • 3
    It's not a bug though, given that the behaviour is specified in the documentation. – Rory Feb 22 '18 at 13:57
  • @Rory Have you got a link to the documentation for reference please. It might not be a bug (although it may be a wetware one?!), but it certainly isn't logical, given that there is an `Add` function explicitly defined. Let's just hope no one has created a nuclear weapons targeting system with a vba dictionary of targets :0) – 3-14159265358979323846264 Feb 22 '18 at 14:10
  • 2
    See the remarks section: https://msdn.microsoft.com/en-us/library/aa243166(v=vs.60).aspx – Rory Feb 22 '18 at 14:15
  • See also: https://stackoverflow.com/questions/48896394/dictionary-exists-returning-different-values-for-variable-and-constant-key/48896896#48896896 Have to be careful using Watches on Dictionary objects. – Tim Williams Feb 22 '18 at 16:02
  • This happens when you try to reference a dictionary with a key or index that isn't in it. It will create a new entry automatically. – peege Nov 12 '20 at 15:41

2 Answers2

4

As you pointed out, you have two different keys, 1 and "1". If you try to access a key that doesn't already exist in the dictionary, it will add it automatically. It is strange behaviour.

I'd use something like this:

If dict.Exists(something) Then
    myVariable = dict.Item(something)
End If
CallumDA
  • 12,025
  • 6
  • 30
  • 52
  • Ok. Thanks. Have upvoted your answer but Jeeped was first so I'm awarding him the answer. I do think that the 'shortcut version automatically adding a new key' is totally nonsensical though. I mean, that's what the `Add` function should be for. Thanks again! – 3-14159265358979323846264 Feb 22 '18 at 13:42
  • @3-14159265358979323846264 Happy to help. But, since Jeeped's answer was useful you should upvote his too! – CallumDA Feb 22 '18 at 13:44
3

You creating one key as a string representing 1 (e.g. "1") and the key's item as the number 1 using the conventional dict.Add <key>,<item>.

Immediately afterwards, you shortcut add another with the number 1 as the key.personally, I shortcut the add/overwrite with dict.item(1) = "abc" but your method works as well.

tbh, I'm not even sure if .CompareMode = vbTextCompare would resolve a string 1 to equal a numeric 1. In any event, you are currently on a vbBinaryCompare so there is no way it will match.

K.Dᴀᴠɪs
  • 9,945
  • 11
  • 33
  • 43
  • 3
    Lol. Ok. So `dict(x)` where `x` isn't already in the dictionary adds an empty lookup value, whereas `dict(x)` where `x` is already in the dictionary returns the lookup value. Am I the only one that thinks this makes no logical sense. A function should surely have a single, well defined, err, function?! – 3-14159265358979323846264 Feb 22 '18 at 13:38
  • But `Item()` *(the default method when implicitly calling `obj()`)* is not a function, [it's a property](https://i.stack.imgur.com/UsOkk.png) - which we know from VBA 101 that properties have the ability to `Get`/`Let`/`Set` values. And dictionaries use key-value pairs, so in order for the dictionary to return you the value of the x key, it has to first "plug" in the x key. Consequently, this means that by doing so it just created a new entry in the table in order to return this value to you. This is why the `.Exists()` function, well um, *Exists*. – K.Dᴀᴠɪs Jul 18 '23 at 19:16