Saltar al contenido

Forma genérica de comprobar si key está en una colección en Excel VBA

Hola, encontramos la solución a tu interrogante, has scroll y la encontrarás más abajo.

Solución:

Deberías usar un Variant en la primera función. Puede asignar un Object a un Variant, por ejemplo, esto no producirá un error:

Sub Test()
    Dim var As Variant
    Dim obj As Object
    Set obj = Application
    var = Application
    Debug.Print var
End Sub

Pero esto le dará un Type Mismatch error de compilación, es decir, tratando de asignar un Long a una Object:

Sub Test()
    Dim obj As Object
    Dim lng As Long
    lng = 3
    Set obj = lng
End Sub

Entonces, para una función genérica (a lo largo de las líneas de su código) para verificar si un Collection key es válido, puede utilizar:

Function HasKey(coll As Collection, strKey As String) As Boolean
    Dim var As Variant
    On Error Resume Next
    var = coll(strKey)
    HasKey = (Err.Number = 0)
    Err.Clear
End Function

Código de prueba:

Sub Test()
    Dim coll1 As New Collection
    coll1.Add Item:=Sheet1.Range("A1"), Key:="1"
    coll1.Add Item:=Sheet1.Range("A2"), Key:="2"
    Debug.Print HasKey(coll1, "1")

    Dim coll2 As New Collection
    coll2.Add Item:=1, Key:="1"
    coll2.Add Item:=2, Key:="2"
    Debug.Print HasKey(coll2, "1")
End Sub

Hay un artículo útil sobre MSDN al respecto. El contexto es VB6 pero se relaciona con VBA.

Algunos errores tipográficos según los comentarios ya se han corregido durante la edición de su publicación. En respuesta a su pregunta, me gustaría cubrir aspectos relacionados.
Durante el uso keys en colecciones tiene principalmente tres ventajas

– Si el pedido cambia, su código seguirá accediendo al artículo correcto – Puede acceder directamente al artículo sin leer toda la colección
– Puede hacer que su código sea más legible.

* Pero al mismo tiempo hay principalmente tres problemas con el uso keys en colecciones

  • No puede comprobar si el key existe

  • No puedes cambiar el key

  • No puede recuperar el key

Según el artículo de Pearsons, las claves de una colección son de solo escritura; no hay forma de obtener una lista de las claves de una colección existentes. Continuando con el párrafo citado: –

Aquí, Coll es un objeto Collection en el que almacenaremos varios objetos CFile. La colección CollKeys se utiliza para almacenar keys de los objetos CFile almacenados en la Colección Coll. Necesitamos esta segunda colección porque las claves de una colección son de solo escritura; no hay forma de obtener una lista de las claves de una colección existentes. Una de las mejoras proporcionadas por CFiles es la capacidad de recuperar una lista de claves para la colección.

Clases de colección personalizadas

Una forma es iterar sobre los miembros de la colección y ver si hay una coincidencia con lo que está buscando y la otra forma es detectar la Item not in collection error y luego establezca una bandera para decir que el elemento no existe. Las opiniones difieren sobre estos enfoques, mientras que algunas personas sienten que no es un buen método para detectar errores, mientras que otras secciones consideran que será significativamente más rápido que la iteración para cualquier colección de tamaño mediano a grande.
Entonces, si buscamos un método para detectar el error, el número de error que obtenemos depende exactamente de qué causó el error. Necesitamos una rutina de código para verificar el error. De la forma más sencilla podría ser.

'c1 is the collection
 For i = 1 To c1.Count
     Debug.Print Err.Number, Err.Description
     If Err.Number <> 0 Then Err.Clear
 Next i

Las rutinas de detección de errores propuestas por varios profesionales difieren en el número de error que consideran importante e incluyen en su rutina. Varios números de error que ocurren comúnmente asociados con el objeto de recolección son:

  • Error 5 Argumento o llamada a procedimiento no válido. Este error también puede ocurrir si se intenta llamar a un procedimiento que no es válido en la plataforma actual. Por ejemplo, es posible que algunos procedimientos solo sean válidos para Microsoft Windows o para Macintosh, etc.
  • error 438 “el objeto no admite esta propiedad o método Un objeto es una instancia de clase. Una instancia de clase admite algunas propiedades definidas en esa definición de tipo de clase y no admite esta.
  • Error 457 Esta key ya está asociado con un elemento de esta colección. key para un miembro de la colección que ya identifica a otro miembro de la colección. Elija una diferente key
    para este miembro.
  • Error 91 Variable de objeto o variable de bloque With no establecida. Hay dos pasos para crear una variable de objeto. Primero debe declarar la variable de objeto. Luego debe asignar una referencia válida a la variable de objeto usando la instrucción Set. Intentó utilizar una variable de objeto que aún no hace referencia a un objeto válido.
  • Error 450 Número incorrecto de argumentos o asignación de propiedad no válida. El número de argumentos en la llamada al procedimiento no era el mismo que el número de argumentos requeridos que esperaba el procedimiento. Si intentó asignar un valor a una propiedad de solo lectura,

Entre los errores anteriores, el error número 438 se ha considerado importante y el otro es 5. Estoy incorporando una rutina de función en mi programa de prueba de muestra que fue publicado por Mark Nold hace 7 años en 2008 vide SO pregunta Determinación de si un objeto es un miembro de una colección en VBA con el debido crédito a él.

Algunos errores, como el error 457, no se permitirán en el momento de la ejecución de la prueba del programa. Traté de poblar con duplicado keys datos, dio el error en el momento de la prueba del programa como se muestra en la instantánea.
error 457

Después de quitarlo, se muestra la salida correcta como se muestra en la instantánea.

No hay error

Puede que no sea posible obtener la lista de keys de una colección con una colección vainilla sin almacenar el key valores en un independiente array. La alternativa más fácil para hacer esto es agregar una referencia a Microsoft Scripting Runtime y usar un diccionario más capaz en su lugar. He incluido este enfoque para obtener la lista de keys en mi programa.
Al poblar la Colección, se debe asegurar que el key es el segundo parámetro y debe ser único string.

El código completo de mi programa es.

Sub Generic_key_check()
    Dim arr As Variant
    Dim c1 As New Collection
    Dim dic As Object
    With Application
    .ScreenUpdating = False
    End With


    Set dic = CreateObject("Scripting.Dictionary")
    dic.CompareMode = vbTextCompare

    'Populate the collection
    c1.Add "sheet1", "sheet1"
    c1.Add "sheet2", "sheet2"
    c1.Add "sheet3", "sheet3"
    c1.Add "sheet4", "sheet4"
    c1.Add "sheet5", "sheet5"
    c1.Add 2014001, "Long1"
    c1.Add 2015001, "Long2"
    c1.Add 2016001, "Long3"
    c1.Add 2015002, "Long4"
    c1.Add 2016002, "Long5"

    'Populate the dictionary
    dic.Add "sheet1", "sheet1"
    dic.Add "sheet2", "sheet2"
    dic.Add "sheet3", "sheet3"
    dic.Add "sheet4", "sheet4"
    dic.Add "sheet5", "sheet5"
    dic.Add "Long1", 2014001
    dic.Add "Long2", 2015001
    dic.Add "Long3", 2016001
    dic.Add "Long4", 2015002
    dic.Add "Long5", 2016002
    ' Get a list of key items by Dictionary Method
    Dim N As Variant
    For Each N In dic.Keys
    Debug.Print "Key: " & N, "Value: " & dic.item(N)
    Next
    'Test for two types of data whether key exists or not.
    If InCollection(c1, "Long1") Then
    'If Exists("Long1", c1) Then
    Debug.Print "Good"

    Else
    ' If there is error then print out the error number and its description.
    Debug.Print Err.Number, Err.Description
    Debug.Print "Not Good"
    End If
    If InCollection(c1, "sheet2") Then
    Debug.Print "Good"

    Else
    Debug.Print Err.Number, Err.Description
    Debug.Print "Not Good"
    End If

    'Checking whether desired key has populated correctly
    Debug.Print c1("Sheet1")
    Debug.Print c1("Long3")



    'Listing out collection items to check theyexist in the collection.
    For i = 1 To c1.Count
    Debug.Print c1.item(i)
    Next i
    With Application
    .ScreenUpdating = True
    End With
    Set c1 = Nothing
End Sub
Public Function InCollection(col As Collection, key As String) As Boolean
    Dim var As Variant
    Dim errNumber As Long

    InCollection = False
    Set var = Nothing

    Err.Clear
    On Error Resume Next
    var = col.item(key)
    errNumber = CLng(Err.Number)
    On Error GoTo 0

    '5 is not in, 0 and 438 represent incollection
    If errNumber = 5 Then ' it is 5 if not in collection
    InCollection = False
    Else
    InCollection = True
    End If

End Function

La salida final según el programa, como se muestra en la ventana Inmediato, se ha mostrado en la instantánea.
ingrese la descripción de la imagen aquí

Quiero señalar que si desea que la función de PaulE sea un poco más flexible, puede cambiar el string parámetro a una variante, lo que significa que ahora también puede usarlo para verificar un elemento key o para un número de artículo, que es útil. Las variantes son un poco más lentas si va a verificar muchas colecciones, pero para la mayoría de los propósitos, las dos funciones actuarán de manera similar.

Function HasItem(col As Collection, ItemKeyOrNum As Variant) As Boolean
    Dim v As Variant
    On Error Resume Next
    v = IsObject(col.Item(ItemKeyOrNum))
    HasItem = Not IsEmpty(v)
End Function

La respuesta aceptada aquí es incorrecta (que es el caso de algunas otras preguntas que también he notado, así que tenga cuidado y lea todas las respuestas). Apostle y PaulE colaboraron allí para obtener la respuesta más correcta a la pregunta específica que se hizo. Intenté usar la respuesta aceptada, pero no funcionó.

La pregunta dice claramente: “¿Hay alguna manera de comprobar si un key está contenida en la Colección que funciona tanto para tipos como para objetos? “

La respuesta aceptada NO funciona para objetos. La respuesta de PaulE es la respuesta final y correcta. Solo estoy agregando un poco de matiz aquí para hacer que la función sea más única para todos.

Reseñas y valoraciones

Tienes la opción de patrocinar nuestro quehacer escribiendo un comentario y valorándolo te lo agradecemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *