Нечувствительный к регистру словарь со строковым ключом в C #


156

Если у меня Dictionary<String,...>есть, можно ли сделать такие методы, как ContainsKeyбез учета регистра?

Это казалось связанным, но я не понял его правильно: c # Dictionary: создание ключа без учета регистра с помощью объявлений


6
Что не так с использованием StringComparer.InvariantCultureIgnoreCase? Он делает то, что говорит ...
Леппи

5
Я никогда не слышал об этом, поэтому вопрос!
Мистер Бой


Этот вопрос связан, но не совсем дублирует этот. Это входит в то, как иметь дело с существующим словарем. Я начинаю с нового кода, поэтому ответы здесь лучше подходят.
Goodeye

Ответы:


322

Это казалось связанным, но я не понял его правильно: c # Dictionary: создание ключа без учета регистра с помощью объявлений

Это действительно связано. Решение состоит в том, чтобы сказать экземпляру словаря не использовать стандартный метод сравнения строк (который чувствителен к регистру), а использовать регистронезависимый. Это делается с помощью соответствующего конструктора :

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

Конструктор ожидает, IEqualityComparerчто словарь говорит, как сравнивать ключи.

StringComparer.InvariantCultureIgnoreCaseдает вам IEqualityComparerэкземпляр, который сравнивает строки без учета регистра.


1
Отлично, я как-то пропустил STL-подобный способ передачи компаратора в ctor.
Мистер Бой

7
Меня не перестает удивлять, как я всегда нахожу здесь ответ на любой вопрос кодирования! Может быть, я назову мою следующую кошку в честь тебя, Конрад! :-)
Джейми

10
Возможно, сравнение StringComparison.OrdinalIgnoreCase быстрее, чем на основе культуры: stackoverflow.com/questions/492799/…
Манушин Игорь

Как мне это сделать, если я не создаю словарь, но пытаюсь использовать ContainsKey () для нечувствительного к регистру совпадения ключей в существующем словаре, который я получаю как часть объекта?
Шридхар Р Кулкарни

1
@ShridharRKulkarni Вы принципиально не можете (эффективно). Логика сравнения является основной частью внутренней структуры данных словаря. Для этого контейнер должен поддерживать несколько индексов для своих данных, а словари этого не делают.
Конрад Рудольф

21
var myDic = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
myDic.Add("HeLlo", "hi");

if (myDic.ContainsKey("hello"))
    Console.WriteLine(myDic["hello"]);

1
Фрагмент кода говорит обо всем. Очень полезно. Не уверен, почему этот пост имеет меньше голосов по сравнению с принятым ответом только за опоздание на 3 минуты.
RBT

14

Есть немного шансов, когда ваше дело со словарем, который извлекается из сторонних или внешних DLL. Используя linq

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


3
Это прекрасно работает. Слово предостережения , хотя, если вы измените Anyк SingleOrDefaultвам не получите nullобратно , если он не существует, вместо этого вы получите KeyValuePair как с ключом и устанавливающим null!
NibblyPig

1
ContainsПохоже, это очень специфический вариант использования того, над чем вы работали в то время. Как более общий полезный ответ, я думаю, что Equalsлучше. И на этой же ноте вместо дублирования строки ToLower()было бы лучше использовать StringComparison.xxxCase.
Суамер

1
это было очень полезно, и избавление от ToLower, безусловно, является улучшением - мой пример использования: return AppliedBuffs.Any (b => b.Key.Equals (Name, StringComparison.OrdinalIgnoreCase)); идеальный регистронезависимый Содержит регистрозависимый словарь.
Дэвид Берфорд

Я так искушаю понизить это. Слово предостережения, если вы являетесь владельцем словаря, это, безусловно, не способ сделать это. Используйте этот подход, только если вы не знаете, как создавался словарь. Даже в этом случае для точного соответствия строки (а не только для совпадения dict.Keys.Contains("bla", appropriate comparer)деталей ) используйте перегрузку LINQ для простоты использования.
Навфал

1

Я просто столкнулся с такой же проблемой, когда мне понадобился регистр символов в контроллере ASP.NET Core.

Я написал метод расширения, который делает свое дело. Может быть, это может быть полезно и для других ...

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

Чтобы использовать метод расширения:

myDictionary.ConvertToCaseInSensitive();

Затем получите значение из словаря с помощью:

myDictionary.ContainsKey("TheKeyWhichIsNotCaseSensitiveAnymore!");

0

Если у вас нет контроля при создании экземпляра, скажем, ваш объект удален от json и т. Д., Вы можете создать класс-оболочку, который наследуется от словарного класса.

public class CaseInSensitiveDictionary<TValue> : Dictionary<string, TValue>
{
    public CaseInSensitiveDictionary() : base(StringComparer.OrdinalIgnoreCase){}
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.