我正在查找Scripting.Dictionary
中的密钥,以确保我只将它们(及其项目)添加到字典中一次:
If MyDict.Exists (Key) Then ' first internal key-value lookup
Set Entry=MyDict.Item (Key) ' Second internal key->value lookup
else
Set Entry=New ItemType
MyDict.Add Key,Entry
End If
' Now I work on Entry...
Exists
查找字典中的密钥,Item ()
也可以查找。所以我得到一个逻辑查找操作的两个键查找。是不是有更好的方法?
Item
属性的dox说
“如果在尝试返回现有项目时未找到密钥,则为新项目 创建密钥并将其相应的项留空。“ (MSDN)
这是真的,即查找一个不存在的键显然使这个字典的关键部分,可能与关联项=空。
但那有什么好处呢? 我如何使用它将其归结为一次查找操作?如何在Item ()
属性调用期间创建密钥后设置空项?
答案 0 :(得分:2)
此代码和输出:
>> 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
所示:
Set d(name) = object
- 如果需要,d(name)将创建密钥槽“name”并且Set赋值将把对象放入相应的值(覆盖Empty或'old'对象('pointer'))。如果你追加一些你真正希望实现的细节,我愿意加上这个答案。
添加了:
如果您(逻辑上)处理具有重复项的键列表,则必须添加新项 在飞行中对象到字典,你无法避免双重查找,因为 你需要检查存在(1.0)和分配(2.0)(也许是新的 创建并赋值(1.5))对象到你的工作变量(参见/ m:a或/ m:b in my 示例代码)。具有提供值的语句的其他语言可能允许
之类的东西if ! (oBJ = dicX( key )) {
oBJ = dicX( key ) = new ItemType()
}
oBJ.doSomething()
没有VBScript的Set vs. Let令人厌恶的东西,比如
oBJ = dicX( key )
If IsEmpty( oBJ ) Then
dicX( key ) = New ItemType
oBJ = dicX( key )
End If
只会为新元素做额外的工作,但这只是一个白日梦。
如果那些双重查找真的很重要(我怀疑 - 你能给出一个论点吗? 或证据?),那么你的程序的整体设计确实很重要。例如: 如果你能把你的工作清单独一无二,那么一切都变得简单了(参见/ m:c in my 样品)。不可否认,我仍然不知道这些变化是否可能 为了你的具体任务。
试验代码:
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
示例输出:
/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]
时序差异可能是由于/ m:c的输出减少造成的 模式,但它强调了不经常做某事的重要性 然后必要的。
答案 1 :(得分:0)
对我来说,关键问题是VBScript迫使我们对对象使用Set
,而Empty
不是对象。我过去用来解决这个问题的一个技巧是使用Array
函数为值创建一个临时占位符。然后我可以检查数组以查看该值是否为对象。适用于您的示例:
tempArr = Array(dict.Item(key))
If IsEmpty(tempArr(0)) Then
' new entry
Set entry = New MyClass
' can't use Add because the key has already been implicitly created
Set dict.Item(key) = entry
Else
' existing entry
Set entry = tempArr(0)
End If
在这种情况下,您还没有消除双重查找,而是将其从“现有条目”案例移至“新条目”案例。