Преобразование ключей IDictionary‹string, string› в нижний регистр (C#)

У меня есть метод, который получает IDictionary в качестве параметра. Теперь я хочу предоставить метод, который извлекает значение из этого словаря, но он должен быть инвариантным к регистру.

Итак, мое решение для этого прямо сейчас состояло в том, чтобы иметь статическую функцию, которая перебирает ключи и преобразует их вLower() следующим образом:

private static IDictionary<ILanguage, IDictionary<string, string>> ConvertKeysToLowerCase(
    IDictionary<ILanguage, IDictionary<string, string>> dictionaries)
{
    IDictionary<ILanguage, IDictionary<string, string>> resultingConvertedDictionaries 
        = new Dictionary<ILanguage, IDictionary<string, string>>();
    foreach(ILanguage keyLanguage in dictionaries.Keys)
    {
        IDictionary<string, string> convertedDictionatry = new Dictionary<string, string>();
        foreach(string key in dictionaries[keyLanguage].Keys)
        {
            convertedDictionatry.Add(key.ToLower(), dictionaries[keyLanguage][key]);
        }
        resultingConvertedDictionaries.Add(keyLanguage, convertedDictionatry);
    }
    return resultingConvertedDictionaries;
}

Теперь это нормально, но все же это довольно большой кусок кода, который противоречит моей идее «чистого и эффективного». Знаете ли вы какие-либо альтернативы этому, чтобы метод словаря .ContainsKey() не различал регистр?


person Community    schedule 02.10.2008    source источник


Ответы (7)


Да - передайте конструктор словаря StringComparer.OrdinalIgnoreCase (или другой компаратор без учета регистра, в зависимости от ваших потребностей в отношении чувствительности к культуре).

person Jon Skeet    schedule 02.10.2008
comment
Спасибо! Это сработало, но мне все еще нужно просмотреть словарь ILanguage и добавить словари ‹string, string› вручную. Я никак не могу избавиться от этого? - person Tigraine; 02.10.2008
comment
Не то, чтобы я мог сразу подумать. Это всего лишь одна петля... вряд ли нечитаемая. Если вы используете .NET 3.5, вы, вероятно, могли бы немного упростить его немного, но я бы не парился. Можете ли вы изменить создателя исходного словаря, чтобы в первую очередь указать нечувствительный к регистру компаратор? - person Jon Skeet; 02.10.2008
comment
Это кажется лучшим решением, поскольку Tigraine хочет добиться сравнения без учета регистра, а преобразование ключей в нижний регистр — это всего лишь один (ненужный) способ добиться этого. - person VVS; 02.10.2008
comment
Я не могу изменить создателя IDictionary, который передается в качестве параметра. Но смена компаратора работает отлично :) Спасибо! - person Tigraine; 02.10.2008
comment
Как-то это не кажется правильным. Пытаясь изменить параметр, я начинаю зависеть от словаря, а не только от IDictionary. Думаю, мне придется переработать код, создающий словарь, или хотя бы абстрагировать его от моей логики поиска. - person Tigraine; 02.10.2008
comment
Зачем вам нужно менять тип параметра? Я не думаю, что вам нужно полагаться на словарь. - person Jon Skeet; 02.10.2008
comment
Я только что прошел 3 часа бизнес-тренинга у своего работодателя, и это самое ценное, чему я научился сегодня. Как долго я смогу купить книгу C# Proverbs by @JonSkeet? Благодарю вас! - person Rob S.; 20.12.2019

При использовании StringDictionary ключи преобразуются в нижний регистр во время создания.

http://simiansoftware.blogspot.com/2008/11/have-const-string-with-ui-description.html

person Community    schedule 09.02.2009

Вы можете использовать ключевое слово var, чтобы избавиться от беспорядка. Технически источник остается прежним. Также я бы просто передал и вернул Dictionary‹string, string›, потому что вы ничего не делаете с этим параметром ILanguage и сделали метод более многоразовым:

private static IDictionary<string, string> ConvertKeysToLowerCase(
    IDictionary<string, string> dictionaries)
{
    var convertedDictionatry = new Dictionary<string, string>();
    foreach(string key in dictionaries.Keys)
    {
        convertedDictionatry.Add(key.ToLower(), dictionaries[key]);
    }
    return convertedDictionatry;
}

... и назовите это так:

// myLanguageDictionaries is of type IDictionary<ILanguage, IDictionary<string, string>>
foreach (var dictionary in myLanguageDictionaries.Keys)
{
  myLanguageDictionaries[dictionary].Value = 
      ConvertKeysToLowerCase(myLanguageDictionaries[dictionary].Value);
}
person VVS    schedule 02.10.2008
comment
Хороший вопрос, но все еще не решает проблему с зацикливанием. Я объединю ваше решение с решением Джона Скита :) Спасибо! - person Tigraine; 02.10.2008
comment
Ну... чтобы изменить каждый элемент в списке, вам нужно коснуться каждого элемента, что всегда приводит к циклу. Конечно, вы можете попытаться запутать это каким-то образом;) - person VVS; 02.10.2008

Вы можете сами наследовать от IDictionary и просто маршалировать вызовы к внутреннему экземпляру Dictionary.

Add(string key, string value) { dictionary.Add(key.ToLowerInvariant(), value) ; }
public string this[string key]
{
    get { return dictionary[key.ToLowerInvariant()]; }
    set { dictionary[key.ToLowerInvariant()] = value; }
}
// And so forth.
person Jonathan C Dickinson    schedule 02.10.2008

System.Collections.Specialized.StringDictionary() может помочь. MSDN заявляет:

«Ключ обрабатывается без учета регистра; он переводится в нижний регистр перед использованием со словарем строк.

В .NET Framework версии 1.0 этот класс использует сравнение строк с учетом языка и региональных параметров. Однако в .NET Framework версии 1.1 и более поздних версиях этот класс использует CultureInfo.InvariantCulture при сравнении строк. Дополнительные сведения о том, как язык и региональные параметры влияют на сравнения и сортировку, см. в разделах Сравнение и сортировка данных для определенного языка и региональных параметров и Выполнение строковых операций, не зависящих от языка и региональных параметров».

person GregUzelac    schedule 16.10.2008

Вы также можете попробовать этот способ

convertedDictionatry = convertedDictionatry .ToDictionary(k => k.Key.ToLower(), k => k.Value.ToLower());
person Community    schedule 26.02.2020

Версия LINQ с использованием методов расширения IEnumerable<T>:


        private static IDictionary<ILanguage, IDictionary<string, string>> ConvertKeysToLowerCase(
            IDictionary<ILanguage, IDictionary<string, string>> dictionaries)
        {
            return dictionaries.ToDictionary(
                x => x.Key, v => CloneWithComparer(v.Value, StringComparer.OrdinalIgnoreCase));
        }

        static IDictionary<K, V> CloneWithComparer<K,V>(IDictionary<K, V> original, IEqualityComparer<K> comparer)
        {
            return original.ToDictionary(x => x.Key, x => x.Value, comparer);
        }
person mancaus    schedule 02.10.2008