J'ai une application qui utilise des DLL gérées. Une de ces DLL renvoie un dictionnaire générique:
Dictionary<string, int> MyDictionary;
Le dictionnaire contient des touches avec majuscules et minuscules.
D'un autre côté, je reçois une liste de clés potentielles (chaîne) mais je ne peux pas garantir le cas. J'essaye d'obtenir la valeur dans le dictionnaire en utilisant les clés. Mais bien sûr, ce qui suit échouera car j'ai une incompatibilité de cas:
bool Success = MyDictionary.TryGetValue( MyIndex, out TheValue );
J'espérais que TryGetValue aurait un indicateur de casse ignoré comme mentionné dans la doc MSDN , mais il semble que ce ne soit pas valide pour les dictionnaires génériques.
Existe-t-il un moyen d'obtenir la valeur de ce dictionnaire en ignorant le cas clé? Existe-t-il une meilleure solution de contournement que la création d'une nouvelle copie du dictionnaire avec le paramètre StringComparer.OrdinalIgnoreCase approprié ?
la source
Réponses:
Il n'y a aucun moyen de spécifier un
StringComparer
au point où vous essayez d'obtenir une valeur. Si vous y pensez"foo".GetHashCode()
et"FOO".GetHashCode()
êtes totalement différent, il n'y a donc aucun moyen raisonnable d'implémenter un get insensible à la casse sur une carte de hachage sensible à la casse.Vous pouvez, cependant, créer un dictionnaire insensible à la casse en premier lieu en utilisant: -
Ou créez un nouveau dictionnaire ne respectant pas la casse avec le contenu d'un dictionnaire sensible à la casse existant (si vous êtes sûr qu'il n'y a pas de collision de cas): -
Ce nouveau dictionnaire utilise alors l'
GetHashCode()
implémentationStringComparer.OrdinalIgnoreCase
ainsicomparer.GetHashCode("foo")
etcomparer.GetHashcode("FOO")
vous donne la même valeur.Alternativement, s'il n'y a que quelques éléments dans le dictionnaire, et / ou que vous n'avez besoin de chercher qu'une ou deux fois, vous pouvez traiter le dictionnaire d'origine comme un
IEnumerable<KeyValuePair<TKey, TValue>>
et simplement le parcourir: -Ou si vous préférez, sans LINQ: -
Cela vous évite le coût de création d'une nouvelle structure de données, mais en retour, le coût d'une recherche est O (n) au lieu de O (1).
la source
default(KeyValuePair<T, U>)
n'est pasnull
- c'est unKeyValuePair
oùKey=default(T)
etValue=default(U)
. Vous ne pouvez donc pas utiliser l'?.
opérateur dans l'exemple LINQ; vous devrez saisirFirstOrDefault()
puis (pour ce cas particulier) vérifier siKey == null
.Pour vous LINQers là-bas qui n'utilisez jamais un constructeur de dictionnaire ordinaire:
la source
Ce n'est pas très élégant mais au cas où vous ne pouvez pas changer la création du dictionnaire, et tout ce dont vous avez besoin est un hack sale, que diriez-vous:
la source
ToUpperInvariant
au lieu deToLower
. msdn.microsoft.com/en-us/library/dd465121%28v=vs.110%29.aspxvar item = MyDictionary.FirstOrDefault(x => x.Key.ToUpperInvariant() == keyValueToCheck.ToUpperInvariant());
dict.Keys.Contains("bla", appropriate comparer)
? De plus, vous n'obtiendrez pas null pour FirstOrDefault car keyvaluepair en C # est une structure.