Ir para o conteúdo

Dictionary(Of) - Informação organizada

Introdução

"Grande responsabilidade advém de um grande poder" é uma frase que se pode aplicar práticamente a tudo o que conhecemos, e na programação informática não é diferente. A evolução tecnológica forçou os programadores informáticos a prevêr volumes de informação cada vez maiores e a velocidades cada vez maiores. É certo que o hardware também evoluíu ao ponto de facilitar a tarefa, mas nunca rápido o suficiente para não apertar muitas empresas ou programadores com conceitos que têm de funcionar, e rápido. Os programadores recorrem a várias técnicas para tratar os enormes volumes de dados. A mais conhecida é provavelmente o "caching"1.

O problema

O verdadeiro problema é como construír a nível abstracto um cache que seja realmente mais rápido e menos custoso do que ir à fonte da informação. E mais importante de tudo, que seja extremamente fácil de se referenciar. Para o efeito, podemos utilizar muitos tipos, mas vamos focar-nos no que deve ser um dos mais importantes para manter caches: Dictionary(Of) (ou Dicionário De). A utilidade dos dicionários pode ser adaptada para um sem fim de aplicações, para além dos caches.

Porquê dicionários?

  • Porque são rápidos
    São, de longe, mais rápidos que uma "Hash Table"2. De facto, conseguem ser 50% mais rápidos que "Hash Tables" em certas operações.
  • Porque são organizados
    Tem acesso instantâneo a determinada informação identificada por uma chave única.
  • Porque não permitem chaves duplicadas
    A informação está organizada por chaves e as chaves não se podem repetir o que é uma situação ideal.
  • Porque permitem múltiplos tipos de dados
    Tanto as chaves como os seus valores podem ser, virtualmente, qualquer tipo de dados.
  • Porque têm os seus métodos de pesquisa
    Para as necessidades básicas de uma pesquisa, os dicionários possuem métodos para se evitarem implementações de ciclos.
  • Porque os posso transportar para qualquer lado
    Como os próprios dicionários são um tipo de dados, podem ser referenciados para, e em qualquer lado.

Como funcionam?

Passemos então à prática. É na verdade muito simples! Cada bloco de código abaixo representa uma operação distinta que se pode executar com um dicionário.

Criação de uma instância

É na criação da instância onde determinamos quais os tipos de dados a tratar com o dicionário.

Dim Pessoal As New Dictionary(Of Integer, String)

O primeiro tipo de dados, Integer, representa a chave e o segundo, String, o valor associado a essa chave.

Adicionar entradas no dicionário

Para adicionar entradas recorremos ao método Add, cujos argumentos são chave e valor.

        Dim Pessoal As New Dictionary(Of Integer, String)

        Pessoal.Add(1, "Maria Albertina")
        Pessoal.Add(2, "Amélia Gertrudes")

Referenciar uma entrada por chave

Para referenciar um valor, basta escrever o nome do dicionário e introduzir a chave entre parênteses.

Dim PessoaComID1 As String = Pessoal(1)

Referenciar uma entrada por chave em segurança

Para tentar apanhar um valor através de uma chave, que poderá existir ou não, utilizamos o método TryGetValue, pois este método referencia o valor encontrado para uma variável, se encontrar o valor, e devolve um Boolean a determinar se o encontrou ou não sem ser necessário controlar a excepção que daí poderia ser lançada.

        Dim ValorEncontrado As String = ""
        Dim Sucesso As Boolean
        Sucesso = Pessoal.TryGetValue(122, ValorEncontrado)

Alterar um valor por chave

Para alterar um valor basta referenciarmos a entrada do dicionário através da chave e atribuír um valor.

Pessoal(1) = "Maria Josefina"

Remover uma entrada por chave

Para remover um valor, basta utilizar o método Remove cujo argumento é a chave.

Pessoal.Remove(1)

Limpar todas as entradas

Para limpar todas as entradas baste recorrer ao método Clear.

Pessoal.Clear()

Determinar existência de chave

Para determinar a existência de determinada chave sem recorrer à implementação de ciclos, usamos o método ContainsKey.

        Dim ExisteNoDicionario As Boolean
        ExisteNoDicionario = Pessoal.ContainsKey(1)

Determinar existência de valor

Para determinar a existência de determinado valor sem recorrer À implementação de ciclos, usamos o método ContainsValue.

        Dim ExisteNoDicionario As Boolean
        ExisteNoDicionario = Pessoal.ContainsValue("Amélia Gertrudes")

Para a operação básica de um dicionário, os blocos anteriores representam tudo o que precisa de saber. No entanto, existem outras operações para necessidades mais específicas. Vamos expôr algumas:

Percorrer todas as chaves de um dicionário

        For Each Chave As Integer In Pessoal.Keys
            Debug.Write("Chave do dicionário Pessoal: " & Chave.ToString)
        Next

Percorrer todos os valores de um dicionário

        For Each Valor As String In Pessoal.Values
            Debug.Write("Valor do dicionário Pessoal: " & Valor)
        Next

Percorrer todos os pares do dicionário

        For Each Par As KeyValuePair(Of Integer, String) In Pessoal
            Dim Chave As Integer = Par.Key
            Dim Valor As String = Par.Value
        Next

Utilizar tipos de dados compostos

Public Class Form1

    'Criamos um tipo de dados composto, como uma estructura com alguns elementos
    Private Structure Pessoa
        Dim Nome As String
        Dim Idade As Integer
        Dim Morada As String
    End Structure

    'Declaramos o nosso dicionário com chaves Integer e valores do tipo composto Pessoa
    Private Pessoal As New Dictionary(Of Integer, Pessoa)

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'Instanciamos um novo tipo composto Pessoa
        Dim P As New Pessoa With {.Nome = "Clara", .Idade = 20, .Morada = "Rua dos morcões, Nº21"}

        'Adicionamos ao dicionário
        Pessoal.Add(1, P)

        'E por fim acedemos ao que acabámos de inserir
        Dim Nome As String = Pessoal(1).Nome
        Dim Idade As Integer = Pessoal(1).Idade
        Dim Morada As String = Pessoal(1).Morada

    End Sub
End Class

Emparelhamento de dicionários

Um exemplo mais complexo será o emparelhamento de dicionários. Como as chaves e os valores podem ser virtualmente qualquer tipo de dados, podem inclusivé ser do seu próprio tipo de dados. No exemplo, emparelhamos 3 dicionários para obter uma estructura organizada.

Public Class Form1
    'Instanciamos 3 dicionários para conter todos os dados, assim estructurados em 3 níveis.
    'Podem existir "n" pessoas, cada uma tem "n" armazéns que contêm coisas. Cada coisa tem um preço
    Private Pessoas As New Dictionary(Of String, Dictionary(Of String, Dictionary(Of String, Double)))
    Private ArmazensPessoais As New Dictionary(Of String, Dictionary(Of String, Double))
    Private ArmazensPessoais2 As New Dictionary(Of String, Dictionary(Of String, Double))
    Private Coisas As New Dictionary(Of String, Double)
    Private Coisas2 As New Dictionary(Of String, Double)
    Private Coisas3 As New Dictionary(Of String, Double)

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Adicionamos, a título experimental, alguns dados aqui

        'Começamos por adiconar algumas coisas e o seu preço
        Coisas.Add("telemovel", 99.99)
        Coisas.Add("brincos", 89.98)
        Coisas.Add("chaleira", 24.99)

        Coisas2.Add("t-shirt", 9.99)
        Coisas2.Add("computador", 499.95)
        Coisas2.Add("secador de cabelo", 15)

        Coisas3.Add("carro", 12000)
        Coisas3.Add("telemovel", 199.99)
        Coisas3.Add("televisao", 499.97)

        'Depois adicionamos os armazéns, referenciando as coisas que neles existem
        ArmazensPessoais.Add("Armazém da esquina", Coisas)
        ArmazensPessoais.Add("Armazém das coisas roubadas", Coisas3)
        ArmazensPessoais2.Add("Armazém ao lado do café", Coisas2)

        'Por fim, duas pessoas cada uma com os seus armazéns
        Pessoas.Add("Manuel Arnês", ArmazensPessoais)
        Pessoas.Add("Maria Falcatrua", ArmazensPessoais2)


        'Agora, para verificar que tudo se encontra perfeitamente armazenado e estructurado, executamos alguns
        'testes

        'Vamos verificar quantas coisas tem o Manuel no armazém da esquina
        Dim CoisasDoManuel As Integer = Pessoas("Manuel Arnês")("Armazém da esquina").Count

        'Vamos verificar quantos armazéns tem o Manuel
        Dim ArmazensDoManuel As Integer = Pessoas("Manuel Arnês").Count

        'Vamos verificar o preço do carro no armazém de coisas roubadas do Manuel
        Dim PrecoCarroRoubado As Double = Pessoas("Manuel Arnês")("Armazém das coisas roubadas")("carro")

        'E por fim, vamos verificar o preço do secador que está no único armazém da Maria
        Dim PrecoSecador As Double = Pessoas("Maria Falcatrua")("Armazém ao lado do café")("secador de cabelo")

        'Também podemos, através de alguma lógica de ciclos, obter informações como por exemplo
        'todos os items de todos os armazéns do Manuel
        For Each ParArmazem As KeyValuePair(Of String, Dictionary(Of String, Double)) In Pessoas("Manuel Arnês")
            For Each ParCoisa As KeyValuePair(Of String, Double) In Pessoas("Manuel Arnês")(ParArmazem.Key)
                MsgBox("Armazém: " & ParArmazem.Key & "  Coisa: " & ParCoisa.Key & "  Preço: " & ParCoisa.Value & "€")
            Next
        Next

    End Sub
End Class

Ir mais além

A utilidade dos dicionários em caching é verdadeiramente incrível. Com alguma prática da sua mecânica e um pouco de imaginação consegue criar um cache abstracto capaz de melhorar a performance de uma aplicação até 1000% se necessário.


  1. Mais informação sobre caches: http://pt.wikipedia.org/wiki/Cache 

  2. Mais informação sobre Hash Tables: http://en.wikipedia.org/wiki/Hash_table