Scripting.Dictionary Lookup-add-if-not-present 只有一键搜索?

标签 scripting dictionary vbscript scripting.dictionary

我正在查找 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 说

"If key is not found when attempting to return an existing item, a new key is created and its corresponding item is left empty." (MSDN)

这是真的,即查找一个不存在的键显然使这个键成为字典的一部分,可能关联的项目=空。 但那有什么用呢? 如何使用它来将其归结为一个查找操作?如何在 Item () 属性调用期间创建键后设置空项?

最佳答案

此代码和输出:

>> 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

显示:

  1. 使用 .Exists 查找不存在的键不会将键添加到字典中(.Count 在#2 处仍然为 0)
  2. 通过 .Item 或 () 访问不存在的键 - 如我的示例代码中赋值的右侧 - 将键/空对添加到字典中;对于某些任务(例如频率计数),这个“有效”,因为 Empty 在字符串连接中被额外视为 0 或“”。这个小尺度autovivification不能用于对象(没有合适的方法将 Empty 映射到程序员想到的任何对象,也没有像 Python 或 VBScript 中的 Ruby 那样的默认魔法)
  3. 如果你必须维护一个命名对象的字典并且可以同时访问名称和它的对象,你可以只写 Set d(name) = object - d(name) will如有必要,创建键槽“name”,Set 赋值会将对象放入相应的值(覆盖 Empty 或“旧”对象(“指针”))。

如果您附加一些关于您真正想要实现的目标的详细信息,我愿意添加到这个答案中。

添加:

如果您(逻辑上)处理具有重复键的列表并且必须添加新的 动态地指向字典,你无法避免双重查找,因为 您需要检查是否存在 (1.0) 并分配 (2.0) (也许是新的 创建并分配 (1.5)) 对象到您的工作变量(请参阅我的/m:a 或/m:b 示例代码)。带有传递值的语句的其他语言可能允许 像

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 样本)。不可否认,我仍然不知道这样的改变是否可能 为您的特定任务。

实验代码:

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 的输出减少造成的 模式,但它强调不要经常做某事的重要性 那么必要的。

关于Scripting.Dictionary Lookup-add-if-not-present 只有一键搜索?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6910996/

相关文章:

VBScript 如果那么,尝试使用参数运行 exe

vbscript - 我需要 "cmd/c"吗?

linux - 正确使用 IO 重定向将用户输入附加到 Linux 脚本中的文件?

c++ - 映射/设置删除迭代器超出范围

c# - 替换 .net 词典

python - 使用 python 如何为三元变量提供 0, 1 , 2 ?

javascript - 我可以从 "NIL"的 JavaScript 知识开始使用 jQuery(或 Node.js)吗?

linux - 从匹配多个模式的一个文件创建新的多个文件的快速方法

scripting - 谷歌云端硬盘 : Move file to folder

vbscript - Windows 7 计划任务 "runs"但不执行任何操作