Dicionários são sempre listados entre as melhores estruturas de dados pois o custo de acesso a um dado registro é O(1), ou seja, não é necessário percorrer todo dataset para encontrar um elemento, basta acessar o seu índice diretamente. Mas como criar dicionários case insensitive? Ou em outras palavras, como criar dicionários que ignorem a forma como uma palavra foi escrita?
O código abaixo armazena o estoque de produtos para uma determinada loja. Sempre que um produto é adicionado ele verifica se o produto já existe, caso exista aumenta a quantidade em estoque, quando não existe cria um novo registro.
namespace Dictionary { public class Store { public Dictionary<string, int> Items = new(); public void Add(string product, int quant) { if (Items.ContainsKey(product)) { Items[product] += quant; } else { Items.Add(product, quant); } } } public static class DictionaryExample { public static void Main() { var store = new Store(); store.Add("Bike", 10); store.Add("bike", 15); store.Add("Skate", 8); foreach (var item in store.Items) { Console.WriteLine($"{item.Key} - {item.Value}"); } Console.ReadKey(); } } }
O problema é que, por padrão, o runtime trata strings como case sensitive, então “Bike”, “BIKE”, …. e “bike” são palavras diferentes, resultando em dois diferentes produtos:
Bike - 10 bike - 15 Skate - 8
Uma solução simples
Uma solução simples para o problema é converter todas as letras do nome do produto para minúsculas ou maiúsculas, usando ToLower ou ToUpper no método Add():
public void Add(string product, int quant) { product = product.ToLower(); if (Items.ContainsKey(product)) { Items[product] += quant; } else { Items.Add(product, quant); } }
O que trará como resultado:
bike - 25 skate - 8
Funciona, mas não é o ideal.
Uma solução eficaz
Uma solução melhor para o problema é especificar ao runtime como ele deve tratar as strings armazenadas no dicionário usando a classe StringComparer no momento que o dicionário é instanciado.
Então, ao invés de instanciar o objeto simplesmente usando new(), basta passar o tipo de comparação desejada no construtor no mesmo. A opção InvariantCultureIgnoreCase fará com que as strings “Bike” e “bike” sejam consideradas a mesma sem a necessidade do uso do método ToLower e produzirá exatamente a mesma saída.
public Dictionary<string, int> Items = new(StringComparer.InvariantCultureIgnoreCase);
Quer saber mais sobre os diferentes tipos de comparação, então acesse a documentação oficial da Microsoft: StringComparer Class