Diccionario sensible a mayúsculas y minúsculas con tipo de clave de cadena en C #

156

Si tengo un ¿ Dictionary<String,...>es posible hacer métodos como ContainsKeymayúsculas y minúsculas?

Esto parecía relacionado, pero no lo entendí correctamente: Diccionario C #: haciendo que la clave no distinga entre mayúsculas y minúsculas a través de declaraciones

Señor chico
fuente
66
¿Qué hay de malo en usar StringComparer.InvariantCultureIgnoreCase? Hace lo que dice ...
leppie
55
Nunca había oído hablar de eso, ¡de ahí la pregunta!
Sr. Boy
Esa pregunta está relacionada, pero no es un duplicado de esta. Ese entra en cómo lidiar con un diccionario existente. Estoy comenzando con un nuevo código, por lo que las respuestas aquí son más adecuadas.
goodeye

Respuestas:

322

Esto parecía relacionado, pero no lo entendí correctamente: Diccionario C #: haciendo que la clave no distinga entre mayúsculas y minúsculas a través de declaraciones

De hecho está relacionado. La solución es decirle a la instancia del diccionario que no use el método estándar de comparación de cadenas (que distingue entre mayúsculas y minúsculas), sino que utilice uno que no distinga entre mayúsculas y minúsculas. Esto se hace usando el constructor apropiado :

var dict = new Dictionary<string, YourClass>(
        StringComparer.InvariantCultureIgnoreCase);

El constructor espera un mensaje IEqualityComparerque le dice al diccionario cómo comparar claves.

StringComparer.InvariantCultureIgnoreCasele ofrece una IEqualityComparerinstancia que compara las cadenas sin distinción entre mayúsculas y minúsculas.

Konrad Rudolph
fuente
1
Perfecto, de alguna manera había echado de menos la forma STL de pasar el comparador al ctor.
Sr. Boy
77
¡Nunca deja de sorprenderme cómo siempre encuentro la respuesta a cualquier pregunta de codificación aquí! ¡Quizás nombre a mi próximo gato después de ti, Konrad! :-)
Jamie
10
Posible, el comparador de StringComparison.OrdinalIgnoreCase más rápido que basado en la cultura: stackoverflow.com/questions/492799/…
Manushin Igor
¿Cómo lo hago si no estoy creando un diccionario pero estoy tratando de usar ContainsKey () para una coincidencia de teclas que no distingue entre mayúsculas y minúsculas en un diccionario existente que obtengo como parte de un objeto?
Shridhar R Kulkarni
1
@ShridharRKulkarni Básicamente no puedes (eficientemente). La lógica de comparación es una parte central de la estructura interna de datos del diccionario. Para permitir esto, el contenedor tendría que mantener múltiples índices para sus datos, y los diccionarios no lo hacen.
Konrad Rudolph
21
var myDic = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
myDic.Add("HeLlo", "hi");

if (myDic.ContainsKey("hello"))
    Console.WriteLine(myDic["hello"]);
Steve
fuente
1
El fragmento de código lo dice todo. Muy útil. No estoy seguro de por qué esta publicación tiene menos votos positivos en comparación con la respuesta aceptada solo por llegar tarde por 3 minutos.
RBT
14

Hay pocas posibilidades de que su trato con el diccionario que se extrae de terceros o dll externo. Usando linq

YourDictionary.Any(i => i.KeyName.ToLower().Contains("yourstring")))

Kurkula
fuente
3
Esto funciona muy bien. Sin embargo, una advertencia: si cambia Anya SingleOrDefaultno nullvolverá si no existe, en su lugar obtendrá un par de valores clave con clave y valor establecidos null.
NibblyPig
1
ContainsParece un caso de uso muy específico para algo en lo que estaba trabajando en ese momento. Como una respuesta útil más genérica, creo que Equalses mejor. Y en esa misma nota, en lugar de duplicar una cadena con ToLower(), sería aún mejor usar StringComparison.xxxCase.
Suamere
1
esto fue muy útil y deshacerse de ToLower es definitivamente una mejora: mi caso de uso fue: return AppliedBuffs.Any (b => b.Key.Equals (Name, StringComparison.OrdinalIgnoreCase)); perfecto entre mayúsculas y minúsculas Contiene en un diccionario de mayúsculas y minúsculas.
David Burford
Estoy tan tentado a menospreciar esto. Una advertencia: si usted es el propietario del diccionario, esta no es la forma de hacerlo. Utilice este enfoque solo si no sabe cómo se creó una instancia del diccionario. Incluso entonces, para la coincidencia exacta de la cadena (no solo la coincidencia parcial), use la dict.Keys.Contains("bla", appropriate comparer)sobrecarga de LINQ para facilitar su uso.
nawfal
1

Me encontré con el mismo tipo de problemas donde necesitaba un diccionario caseINsensitive en un controlador ASP.NET Core.

Escribí un método de extensión que hace el truco. Quizás esto también pueda ser útil para otros ...

public static IDictionary<string, TValue> ConvertToCaseInSensitive<TValue>(this IDictionary<string, TValue> dictionary)
{
    var resultDictionary = new Dictionary<string, TValue>(StringComparer.InvariantCultureIgnoreCase);
    foreach (var (key, value) in dictionary)
    {
        resultDictionary.Add(key, value);
    }

    dictionary = resultDictionary;
    return dictionary;
}

Para usar el método de extensión:

myDictionary.ConvertToCaseInSensitive();

Luego obtenga un valor del diccionario con:

myDictionary.ContainsKey("TheKeyWhichIsNotCaseSensitiveAnymore!");
Ferry Jongmans
fuente
0

Si no tiene control en la creación de la instancia, supongamos que su objeto está desterilizado de json, etc., puede crear una clase de envoltura que herede de la clase de diccionario.

public class CaseInSensitiveDictionary<TValue> : Dictionary<string, TValue>
{
    public CaseInSensitiveDictionary() : base(StringComparer.OrdinalIgnoreCase){}
}
AG
fuente