Dictionnaire sensible à la casse avec type de clé de chaîne en C #

156

Si j'ai un Dictionary<String,...>est-il possible de faire des méthodes comme la ContainsKeycasse insensible?

Cela semblait lié, mais je ne l'ai pas bien compris: c # Dictionary: rendre la clé insensible à la casse grâce aux déclarations

Monsieur Boy
la source
6
Quel est le problème avec l'utilisation StringComparer.InvariantCultureIgnoreCase? Il fait ce qu'il dit ...
leppie
5
Je n'en avais jamais entendu parler, d'où la question!
M. Boy
2
Possible duplication de l' accès insensible à la casse pour le dictionnaire générique
Michael Freidgeim
Cette question est liée, mais pas tout à fait une duplication de celle-ci. Celui-ci explique comment gérer un dictionnaire existant. Je commence avec un nouveau code, donc les réponses ici sont mieux adaptées.
goodeye

Réponses:

322

Cela semblait lié, mais je ne l'ai pas bien compris: c # Dictionary: rendre la clé insensible à la casse grâce aux déclarations

C'est en effet lié. La solution est de dire à l'instance de dictionnaire de ne pas utiliser la méthode standard de comparaison de chaînes (qui est sensible à la casse) mais plutôt d'utiliser une méthode insensible à la casse. Cela se fait en utilisant le constructeur approprié :

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

Le constructeur attend un IEqualityComparerqui indique au dictionnaire comment comparer les clés.

StringComparer.InvariantCultureIgnoreCasevous donne une IEqualityComparerinstance qui compare les chaînes de manière insensible à la casse.

Konrad Rudolph
la source
1
Parfait, j'avais en quelque sorte manqué la manière de passer le comparateur dans le ctor.
Mr. Boy
7
Cela ne cesse de m'étonner de voir comment je trouve toujours la réponse à toute question de codage ici! Peut-être que je vais nommer mon prochain chat après vous, Konrad! :-)
Jamie
10
Possible, le comparateur StringComparison.OrdinalIgnoreCase plus rapide que basé sur la culture: stackoverflow.com/questions/492799/…
Manushin Igor
Comment faire si je ne crée pas de dictionnaire mais que j'essaie d'utiliser ContainsKey () pour une correspondance de clé insensible à la casse sur un dictionnaire existant que j'obtiens dans le cadre d'un objet?
Shridhar R Kulkarni
1
@ShridharRKulkarni Vous ne pouvez fondamentalement pas (efficacement). La logique de comparaison est un élément central de la structure de données interne du dictionnaire. Pour permettre cela, le conteneur devrait conserver plusieurs index pour ses données, et les dictionnaires ne le font pas.
Konrad Rudolph
21
var myDic = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
myDic.Add("HeLlo", "hi");

if (myDic.ContainsKey("hello"))
    Console.WriteLine(myDic["hello"]);
Steve
la source
1
L'extrait de code dit tout. Très utile. Je ne sais pas pourquoi ce message a si moins de votes positifs que la réponse acceptée juste pour être en retard de 3 minutes.
RBT
14

Il y a peu de chances que votre affaire avec un dictionnaire qui est extrait d'une DLL tierce ou externe. Utilisation de linq

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

Kurkula
la source
3
Cela fonctionne très bien. Un mot d'avertissement cependant, si vous changez Anyen, SingleOrDefaultvous ne reviendrez pas nulls'il n'existe pas, vous obtiendrez à la place une paire de valeurs clés avec la clé et la valeur définies sur null!
NibblyPig
1
ContainsCela semble être un cas d'utilisation très spécifique à quelque chose sur lequel vous travailliez à l'époque. En tant que réponse utile plus générique, je pense que Equalsc'est mieux. Et sur cette même note, au lieu de dupliquer une chaîne avec ToLower(), il serait encore mieux de l'utiliser StringComparison.xxxCase.
Suamere
1
cela a été très utile et se débarrasser de ToLower est définitivement une amélioration - mon cas d'utilisation était: return AppliedBuffs.Any (b => b.Key.Equals (Name, StringComparison.OrdinalIgnoreCase)); une parfaite insensible à la casse Contient sur un dictionnaire sensible à la casse.
David Burford
Je suis tellement tenté de voter contre cela. Attention, si vous êtes le propriétaire du dictionnaire, ce n'est certainement pas la façon de procéder. N'utilisez cette approche que si vous ne savez pas comment le dictionnaire a été instancié. Même dans ce cas, pour une correspondance exacte de la chaîne (pas seulement une correspondance partielle), utilisez la dict.Keys.Contains("bla", appropriate comparer)surcharge LINQ pour faciliter l'utilisation.
nawfal
1

Je viens de rencontrer le même genre de problème où j'avais besoin d'un dictionnaire sensible à la casse dans un contrôleur ASP.NET Core.

J'ai écrit une méthode d'extension qui fait l'affaire. Peut-être que cela peut également être utile pour les autres ...

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;
}

Pour utiliser la méthode d'extension:

myDictionary.ConvertToCaseInSensitive();

Ensuite, récupérez une valeur du dictionnaire avec:

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

Si vous n'avez aucun contrôle sur la création de l'instance, disons que votre objet est déstérilisé de json, etc., vous pouvez créer une classe wrapper qui hérite de la classe de dictionnaire.

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