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