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.

5
  • 3
    It's not a bug though, given that the behaviour is specified in the documentation. Commented Feb 22, 2018 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) Commented Feb 22, 2018 at 14:10
  • 2
    See the remarks section: msdn.microsoft.com/en-us/library/aa243166(v=vs.60).aspx Commented Feb 22, 2018 at 14:15
  • See also: stackoverflow.com/questions/48896394/… Have to be careful using Watches on Dictionary objects. Commented Feb 22, 2018 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. Commented Nov 12, 2020 at 15:41

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

2 Comments

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 Happy to help. But, since Jeeped's answer was useful you should upvote his too!
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.

2 Comments

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?!
But Item() (the default method when implicitly calling obj()) is not a function, it's a property - 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.