“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 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.
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.
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.
É 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.
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")
Para referenciar um valor, basta escrever o nome do dicionário e introduzir a chave entre parênteses.
Dim PessoaComID1 As String = Pessoal(1)
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)
Para alterar um valor basta referenciarmos a entrada do dicionário através da chave e atribuír um valor.
Pessoal(1) = "Maria Josefina"
Para remover um valor, basta utilizar o método Remove cujo argumento é a chave
Pessoal.Remove(1)
Para limpar todas as entradas baste recorrer ao método Clear
Pessoal.Clear()
Para determinar a existência de determinada chave sem recorrer a implementação de ciclos, usamos o método ContainsKey
Dim ExisteNoDicionario As Boolean ExisteNoDicionario = Pessoal.ContainsKey(1)
Para determinar a existência de determinado valor sem recorrer a 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:
For Each Chave As Integer In Pessoal.Keys Debug.Write("Chave do dicionário Pessoal: " & Chave.ToString) Next
For Each Valor As String In Pessoal.Values Debug.Write("Valor do dicionário Pessoal: " & Valor) Next
For Each Par As KeyValuePair(Of Integer, String) In Pessoal Dim Chave As Integer = Par.Key Dim Valor As String = Par.Value Next
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
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
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 o performance de uma aplicação até 1000% se necessário.