sábado, 1 de febrero de 2020

Cargar y leer diccionarios en Visual Basic.net


Para muchas aplicaciones es interesante crear y administrar grupos de objetos relacionados. Existen dos formas de agrupar objetos: con matrices de objetos y con colecciones (diccionarios) de objetos.
Los diccionarios proporcionan una manera más flexible de trabajar con grupos de objetos. A diferencia de las matrices, el grupo de objetos con el que trabaja puede aumentar y reducirse de manera dinámica. Para algunos diccionarios, podemos asignar una clave a cualquier objeto que incluyamos en la colección y de este modo, recuperar rápidamente el objeto con la clave.



Un diccionario es una clase, por lo que debemos declarar una instancia de la clase para poder agregar elementos a dicho diccionario.
Si el diccionario contiene elementos de un solo tipo de datos. Un diccionario genérico cumple la seguridad de tipos para que no se pueda agregar a él ningún otro tipo de datos. Cuando recuperamos un elemento de un diccionario genérico, no tenemos que determinar su tipo de datos ni convertirlo.

Lo interesante de utilizar diccionarios, es que no es necesario acceder a la base de datos ni recorrer el resulset entero, basta con preguntar si cada valor del resulset que deseamos tratar está o no dentro del diccionario previamente cargado.
A continuación se muestra el código necesario para crear un diccionario y cargarlo con el resultado de una select.

Sub EquivalenciasDominios(ByVal strCarpetaTratar As String, Optional ByVal Carpeta As RepositoryFolder = Nothing)
      
        DS = New DataSet
    
        Dim tb As DataTable
        Dim srSQL As StreamReader
        Dim strConsulta As String

        Dim cmdbuilder As OleDbCommandBuilder
        Dim dA As New OleDbDataAdapter
        Dim Diccionario As New Dictionary(Of String, String)

        Dim MiFila As String
      
        tb = New DataTable

' CargarDiccionario.sql es una select que devuelve dos columnas
        strStartupPath = My.Application.Info.DirectoryPath
        srSQL = New System.IO.StreamReader(strStartupPath & "\CargarDiccionario.sql")


        strConsulta = srSQL.ReadToEnd
        cmdPD = New OleDb.OleDbCommand(strConsulta, cnxPD)
        dA.SelectCommand = cmdPD
        cmdbuilder = New OleDbCommandBuilder(dA)
        dA.Fill(DS, "Diccionario")

'Aquí cargo el diccionario con el resultado de la select CargarDiccionario.sql
        For Each dr As DataRow In DS.Tables("Diccionario").Rows
            If Not Diccionario.ContainsKey(dr("CLAVE")) Then
                Diccionario.Add(dr("CLAVE"), dr("VALOR"))
            End If
        Next

'Si queremos meter varios campos como valor podemos concatenarlos en un string
'Luego se leeran igual que si fuere uno solo

        For Each dr As DataRow In DS.Tables("Diccionario").Rows
            If Not Diccionario.ContainsKey(dr("CLAVE")) Then
                Diccionario.Add(dr("CLAVE"), dr("VALOR1") & "#" & dr("VALOR2"))
            End If
        Next

Una vez tenemos el diccionario cargado podemos recorrelo entero para obtener sus valores del siguiente modo:

  'Aqui leemos el diccionario secuencialmente
  Dim Par As KeyValuePair(Of String, String)
   For Each Par In Diccionario
'Carga la clave y los valores del diccionario
      MiFila = Par.Key & "=" & Par.Value 
   Next         

Pero lo realmente interesante no consiste en leer secuencialmente el diccionario. Suponemos que hay que recorrer una tabla entera con miles de filas y buscar para cada fila si el valor leído se encuentra dentro de nuestro diccionario. Si procedemos del modo mostrado arriba, por cada fila de la tabla tendríamos que recorrer el diccionario entero, si por ejemplo el diccionario tiene miles de pares [clave, valor] , y la tabla que recorremos tiene también miles de filas, tendremos que hacer millones de comparaciones con un retraso considerable para nuestro programa.

La forma más óptima de hacerlo, y para eso se utilizan los diccionarios, es preguntar para cada fila de la tabla, si está contenida en el diccionario (con la cláusula ContainsKey), una sola vez y con una única línea de código de esta forma:

Dim Clave1 as string
Dim Valor1 as string
Dim Valor2 as String
For Each fila In Filas.Table

           
        strClave = fila.valor

        If Diccionario.ContainsKey(strClave) Then
 'Aquí hago el tratamiento si lo encuentro
 'Obtengo el valor correspondiente a la clave (en este caso vienen dos valores                      'concatenados con # para cada valor de la clave)
         MiFila = Diccionario(strClave)

         Dim strFila() As String
         strFila = Split(MiFila, "#")
         Valor1= strFila(0)
         Valor2 = strFila(1)
                     
        Else
'Aquí hago el tratamiento si no lo encuentro
        End if   
Next


Si lo que queremos es modificar un valor de un diccionario, lo podemos buscar directamente por la clave, no es necesario recorrerlo con un for each.

Dim valor_ant As String

Dim valor_nuevo As String

valor_ant = Diccionario("clave")

valor_nuevo = valor_ant + [Tratamiento]

Diccionario_Procesos("clave") = valor_nuevo

Para borrar el diccionario hacemos :

'Borra el diccionario

Dim strKey As String

For Each Linea In Diccionario

    strKey = Linea.Key

    Diccionario.Remove(Linea.Key)

Next

No hay comentarios:

Publicar un comentario