Acceso que no distingue entre mayúsculas y minúsculas para el diccionario genérico
Tengo una aplicación que utiliza DLL administrados. Uno de esos dlls devuelve un diccionario genérico:
Dictionary<string, int> MyDictionary;
El diccionario contiene claves con mayúsculas y minúsculas.
Por otro lado, obtengo una lista de claves potenciales (cadena), sin embargo, no puedo garantizar el caso. Estoy intentando obtener el valor en el diccionario usando las claves. Pero, por supuesto, lo siguiente fallará ya que tengo un caso que no coincide:
bool Success = MyDictionary.TryGetValue( MyIndex, out TheValue );
Esperaba que TryGetValue tuviera un indicador de ignorar mayúsculas y minúsculas como se menciona en el documento de MSDN , pero parece que esto no es válido para diccionarios genéricos.
¿Hay alguna manera de obtener el valor de ese diccionario ignorando el caso clave? ¿Existe una solución mejor que crear una nueva copia del diccionario con el parámetro StringComparer.OrdinalIgnoreCase adecuado?
No hay forma de especificar a StringComparer
en el punto en el que intenta obtener un valor. Si lo piensa bien, "foo".GetHashCode()
son "FOO".GetHashCode()
totalmente diferentes, por lo que no hay una forma razonable de implementar un get que no distinga entre mayúsculas y minúsculas en un mapa hash que distinga entre mayúsculas y minúsculas.
Sin embargo, puede crear un diccionario que no distinga entre mayúsculas y minúsculas usando:-
var comparer = StringComparer.OrdinalIgnoreCase;
var caseInsensitiveDictionary = new Dictionary<string, int>(comparer);
O cree un nuevo diccionario que no distinga entre mayúsculas y minúsculas con el contenido de un diccionario existente que distinga entre mayúsculas y minúsculas (si está seguro de que no hay colisiones entre mayúsculas y minúsculas): -
var oldDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
var newDictionary = new Dictionary<string, int>(oldDictionary, comparer);
Este nuevo diccionario luego usa la GetHashCode()
implementación StringComparer.OrdinalIgnoreCase
y le da el comparer.GetHashCode("foo")
mismo comparer.GetHashcode("FOO")
valor.
Alternativamente, si solo hay unos pocos elementos en el diccionario, y/o solo necesita buscar una o dos veces, puede tratar el diccionario original como un diccionario IEnumerable<KeyValuePair<TKey, TValue>>
y simplemente iterarlo:-
var myKey = ...;
var myDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
var value = myDictionary.FirstOrDefault(x => String.Equals(x.Key, myKey, comparer)).Value;
O si lo prefieres, sin LINQ:-
var myKey = ...;
var myDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
int? value;
foreach (var element in myDictionary)
{
if (String.Equals(element.Key, myKey, comparer))
{
value = element.Value;
break;
}
}
Esto le ahorra el costo de crear una nueva estructura de datos, pero a cambio el costo de una búsqueda es O(n) en lugar de O(1).
Para los usuarios de LINQ que nunca utilizan un constructor de diccionario normal
myCollection.ToDictionary(x => x.PartNumber, x => x.PartDescription, StringComparer.OrdinalIgnoreCase)
Hay una forma mucho más sencilla:
using System;
using System.Collections.Generic;
....
var caseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
No es muy elegante, pero en caso de que no puedas cambiar la creación del diccionario y todo lo que necesitas es un truco sucio, ¿qué tal esto?
var item = MyDictionary.Where(x => x.Key.ToLower() == MyIndex.ToLower()).FirstOrDefault();
if (item != null)
{
TheValue = item.Value;
}