This code and output:
>> Set d = CreateObject("Scripting.Dictionary")
>> WScript.Echo 0, d.Count
>> If d.Exists("soon to come") Then : WScript.Echo 1, d.Count : End If
>> WScript.Echo 2, d.Count
>> d("soon to come") = d("soon to come") + 1
>> WScript.Echo 3, d.Count, d("soon to come")
>>
0 0
2 0
3 1 1
shows:
- Looking up a non existing key with .Exists does not add the key to the dictionary (.Count is still 0 at #2)
- Accessing a non existing key via .Item or () - as on the right hand side of the assignment in my sample code - adds a key/Empty pair to the dictionary; for some task (e.g. frequency counting) this 'works', because Empty is treated as 0 in addition or "" in string concatenation. This small scale autovivification can't be used for objects (no decent way to map Empty to whatever object the programmer thinks off and no default magic as in Python or Ruby in VBScript)
- If you have to maintain a dictionary of named objects and can access the name and its object at the same time, you can just write
Set d(name) = object
- d(name) will create the key slot "name" if necessary and the Set assignment will put the object into the corresponding value (overwriting Empty or the 'old' object ('pointer')).
If you append some details about what you really want to achieve, I'm willing to add to this answer.
Added:
If you (logically) work on a list of keys with duplicates and must add new
objects to the dictionary on the fly, you can't avoid the double lookup, because
you need to check for existence (1.0) and assign (2.0) the (perhaps newly
created and assigned(1.5)) object to your work variable (see /m:a or /m:b in my
sample code). Other languages with statements that deliver a value may allow
something like
if ! (oBJ = dicX( key )) {
oBJ = dicX( key ) = new ItemType()
}
oBJ.doSomething()
and without VBScript's Set vs. Let abomination something like
oBJ = dicX( key )
If IsEmpty( oBJ ) Then
dicX( key ) = New ItemType
oBJ = dicX( key )
End If
would do the extra work for new elements only, but all that is a pipe dream.
If those double lookups really matter (which I doubt - can you give an argument
or evidence?), then the overall design of your program does matter. For example:
If you can unique-fy your work list, everything becomes simple (see /m:c in my
sample). Admittedly, I still have no idea, whether such changes are possible
for your specific task.
Code to experiment with:
Dim dicX : Set dicX = CreateObject( "Scripting.Dictionary" )
Dim aKeys : aKeys = Split( "1 2 3 4 4 3 2 1 5" )
Dim sMode : sMode = "a"
Dim oWAN : Set OWAN = WScript.Arguments.Named
If oWAN.Exists( "m" ) Then sMode = oWAN( "m" )
Dim sKey, oBJ
Select Case sMode
Case "a"
For Each sKey In aKeys
If Not dicX.Exists( sKey ) Then
Set dicX( sKey ) = New cItemType.init( sKey )
End If
Set oBJ = dicX( sKey )
WScript.Echo oBJ.m_sInfo
Next
Case "b"
For Each sKey In aKeys
If IsEmpty( dicX( sKey ) ) Then
Set dicX( sKey ) = New cItemType.init( sKey )
End If
Set oBJ = dicX( sKey )
WScript.Echo oBJ.m_sInfo
Next
Case "c"
aKeys = uniqueList( aKeys )
For Each sKey In aKeys
Set dicX( sKey ) = New cItemType.init( sKey )
Set oBJ = dicX( sKey )
WScript.Echo oBJ.m_sInfo
Next
Case Else
WScript.Echo "Unknown /m:" & sMode & ", pick one of a, b, c."
End Select
WScript.Echo "----------"
For Each sKey In dicX.Keys
WScript.Echo dicX( sKey ).m_sInfo
Next
Dim g_ITCnt : g_ITCnt = 0
Class cItemType
Public m_sInfo
Public Function init( sKey )
Set init = Me
g_ITCnt = g_ITCnt + 1
m_sInfo = "Obj for " & sKey & " (" & g_ITCnt & ")"
End Function
End Class ' cItemType
Function uniqueList( aX )
Dim dicU : Set dicU = CreateObject( "Scripting.Dictionary" )
Dim vX
For Each vX in aX
dicU( vX ) = Empty
Next
uniqueList = dicU.Keys
End Function
sample output:
/m:a
Obj for 1 (1)
Obj for 2 (2)
Obj for 3 (3)
Obj for 4 (4)
Obj for 4 (4)
Obj for 3 (3)
Obj for 2 (2)
Obj for 1 (1)
Obj for 5 (5)
----------
Obj for 1 (1)
Obj for 2 (2)
Obj for 3 (3)
Obj for 4 (4)
Obj for 5 (5)
==================================================
xpl.vbs: Erfolgreich beendet. (0) [0.07031 secs]
/m:c
Obj for 1 (1)
Obj for 2 (2)
Obj for 3 (3)
Obj for 4 (4)
Obj for 5 (5)
----------
Obj for 1 (1)
Obj for 2 (2)
Obj for 3 (3)
Obj for 4 (4)
Obj for 5 (5)
================================================
xpl.vbs: Erfolgreich beendet. (0) [0.03906 secs]
The timing difference is probably caused by the reduced output of the /m:c
mode, but it emphasizes the importance of not doing something more often
then necessary.