scripting - tutorial - solidity español
Scripting.Dictionary Lookup-add-if-not-present con solo una búsqueda de clave? (2)
Este código y salida:
>> 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
muestra:
- Buscar una clave no existente con .Exists no agrega la clave al diccionario (.Count sigue siendo 0 en el n. ° 2)
- Acceder a una clave no existente a través de .Item o () - como en el lado derecho de la asignación en mi código de muestra - agrega una clave / par vacío al diccionario; para alguna tarea (por ejemplo, conteo de frecuencia) esto ''funciona'', porque Vacío se trata como 0 además o "" en la concatenación de cadenas. Esta autovigilancia a pequeña escala no se puede usar para objetos (no hay una forma decente para asignar Empty a cualquier objeto que el programador piense y ninguna magia predeterminada como en Python o Ruby en VBScript)
- Si tiene que mantener un diccionario de objetos nombrados y puede acceder al nombre y a su objeto al mismo tiempo, puede escribir
Set d(name) = object
- d (name) creará el "nombre" de ranura de clave si es necesario y la asignación de Set colocará el objeto en el valor correspondiente (sobreescribiendo Empty o el objeto ''antiguo'' (''puntero'')).
Si agrega algunos detalles sobre lo que realmente desea lograr, estoy dispuesto a agregar a esta respuesta.
Adicional:
Si (lógicamente) trabaja en una lista de claves con duplicados y debe agregar nuevos objetos al diccionario sobre la marcha, no puede evitar la doble búsqueda, porque necesita verificar la existencia (1.0) y asignar (2.0) la (tal vez el objeto recién creado y asignado (1.5)) a su variable de trabajo (vea / m: a o / m: b en mi código de muestra). Otros lenguajes con declaraciones que entregan un valor pueden permitir algo como
if ! (oBJ = dicX( key )) {
oBJ = dicX( key ) = new ItemType()
}
oBJ.doSomething()
y sin VBScript''s Set vs. Let Abomination algo así como
oBJ = dicX( key )
If IsEmpty( oBJ ) Then
dicX( key ) = New ItemType
oBJ = dicX( key )
End If
haría el trabajo extra solo por nuevos elementos, pero todo eso es un sueño imposible.
Si esas búsquedas dobles realmente importan (lo que dudo, ¿puede dar un argumento o evidencia?), Entonces el diseño general de su programa sí importa. Por ejemplo: si puede hacer una lista de trabajo única, todo se vuelve simple (vea / m: c en mi ejemplo). Es cierto, todavía no tengo idea, si tales cambios son posibles para su tarea específica.
Código para experimentar con:
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
muestra de salida:
/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]
La diferencia de tiempo es probablemente causada por la salida reducida del modo / m: c, pero enfatiza la importancia de no hacer algo más a menudo de lo necesario.
Estoy buscando claves en un Scripting.Dictionary
para asegurarme de que las agregue (y sus elementos) solo una vez al diccionario:
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
busca la clave en el diccionario, y Item ()
también lo hace. Así que obtengo dos búsquedas clave para una operación de búsqueda lógica. ¿No hay una mejor manera?
La dox para la propiedad del Item
dice
"Si no se encuentra la clave al intentar devolver un artículo existente, se crea una nueva clave y su artículo correspondiente se deja vacío". ( MSDN )
Esto es cierto, es decir, buscar una clave inexistente obviamente hace que esta parte clave del diccionario, probablemente con el elemento asociado = vacío. Pero, ¿para qué sirve eso? ¿Cómo podría usar esto para reducirlo a una sola operación de búsqueda? ¿Cómo puedo configurar el elemento vacío después de crear la clave durante la llamada a la propiedad Item ()
?
El problema clave para mí es el hecho de que VBScript nos obliga a usar Set
con objetos, y Empty
no es un objeto. Un truco que he usado en el pasado para evitar esto es usar la función Array
para crear un marcador de posición temporal para el valor. Luego puedo verificar la matriz para ver si el valor es un objeto o no. Aplicado a tu ejemplo:
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
Sin embargo, en este caso, no ha eliminado la búsqueda doble, sino que la ha movido del caso de "entrada existente" al caso de "entrada nueva".