Каков наилучший способ перебора словаря?

Я видел несколько разных способов перебора словаря в C #. Есть ли стандартный способ?

вопрос задан 26.09.2008
Jake Stewart
10191 репутация

25 ответов


  • 2980 рейтинг
    foreach(KeyValuePair entry in myDictionary)
    {
        // do something with entry.Value or entry.Key
    }
    
    ответ дан Pablo Fernandez, с репутацией 66388, 26.09.2008
  • 670 рейтинг

    Если вы пытаетесь использовать универсальный словарь в C #, как если бы вы использовали ассоциативный массив на другом языке:

    foreach(var item in myDictionary)
    {
      foo(item.Key);
      bar(item.Value);
    }
    

    Или, если вам нужно только перебрать коллекцию ключей, используйте

    foreach(var item in myDictionary.Keys)
    {
      foo(item);
    }
    

    И, наконец, если вас интересуют только значения:

    foreach(var item in myDictionary.Values)
    {
      foo(item);
    }
    

    (Обратите внимание, что ключевое слово var является необязательным C # 3. 0 и выше, вы также можете использовать точный тип ваших ключей / значений здесь)

    ответ дан Jacob, с репутацией 17241, 26.09.2008
  • 111 рейтинг

    В некоторых случаях вам может понадобиться счетчик, который может быть предоставлен реализацией цикла for. Для этого LINQ предоставляет ElementAt , что позволяет следующее:

    for (int index = 0; index < dictionary.Count; index++) {
      var item = dictionary.ElementAt(index);
      var itemKey = item.Key;
      var itemValue = item.Value;
    }
    
    ответ дан Maurício Fedatto, с репутацией 1591, 10.03.2011
  • 75 рейтинг

    Зависит от того, хотите ли вы получить ключи или значения. , ,

    Из MSDN Dictionary(TKey, TValue) Описание класса:

    // When you use foreach to enumerate dictionary elements,
    // the elements are retrieved as KeyValuePair objects.
    Console.WriteLine();
    foreach( KeyValuePair kvp in openWith )
    {
        Console.WriteLine("Key = {0}, Value = {1}", 
            kvp.Key, kvp.Value);
    }
    
    // To get the values alone, use the Values property.
    Dictionary.ValueCollection valueColl =
        openWith.Values;
    
    // The elements of the ValueCollection are strongly typed
    // with the type that was specified for dictionary values.
    Console.WriteLine();
    foreach( string s in valueColl )
    {
        Console.WriteLine("Value = {0}", s);
    }
    
    // To get the keys alone, use the Keys property.
    Dictionary.KeyCollection keyColl =
        openWith.Keys;
    
    // The elements of the KeyCollection are strongly typed
    // with the type that was specified for dictionary keys.
    Console.WriteLine();
    foreach( string s in keyColl )
    {
        Console.WriteLine("Key = {0}", s);
    }
    
    ответ дан J Healy, с репутацией 1784, 26.09.2008
  • 56 рейтинг

    Обычно спрашивать «лучший способ» без определенного контекста - это все равно, что спрашивать, какой цвет лучше.

    С одной стороны, есть много цветов и нет лучшего цвета. Это зависит от необходимости и часто от вкуса тоже.

    С другой стороны, существует много способов перебора словаря в C #, и лучшего способа нет. Это зависит от необходимости и часто от вкуса тоже.

    Самый простой способ

    foreach (var kvp in items)
    {
        // key is kvp.Key
        doStuff(kvp.Value)
    }
    

    Если вам нужно только значение (позволяет назвать его item, более читабельно, чем kvp.Value).

    foreach (var item in items.Values)
    {
        doStuff(item)
    }
    

    Если вам нужен определенный порядок сортировки

    Как правило, новички удивляются порядку перечисления словаря.

    LINQ предоставляет краткий синтаксис, который позволяет указывать порядок (и многое другое), e. г. :

    foreach (var kvp in items.OrderBy(kvp => kvp.Key))
    {
        // key is kvp.Key
        doStuff(kvp.Value)
    }
    

    Опять же, вам может понадобиться только значение. LINQ также предоставляет краткое решение для:

    • итерация непосредственно по значению (позволяет назвать его item, более читабельным, чем kvp.Value)
    • но отсортировано по ключам

    Вот оно:

    foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
    {
        doStuff(item)
    }
    

    Есть много других реальных вариантов использования, которые вы можете сделать из этих примеров. Если вам не нужен конкретный заказ, просто придерживайтесь «самого простого способа» (см. Выше)!

    ответ дан Stéphane Gourichon, с репутацией 2858, 10.08.2015
  • 38 рейтинг

    Я бы сказал, что foreach - это стандартный способ, хотя он, очевидно, зависит от того, что вы ищете.

    foreach(var kvp in my_dictionary) {
      ...
    }
    

    Это то, что вы ищете?

    ответ дан George Mauer, с репутацией 47265, 26.09.2008
  • 29 рейтинг

    Вы также можете попробовать это в больших словарях для многопоточной обработки.

    dictionary
    .AsParallel()
    .ForAll(pair => 
    { 
        // Process pair.Key and pair.Value here
    });
    
    ответ дан Onur, с репутацией 490, 11.06.2015
  • 22 рейтинг

    Есть много вариантов. Мой личный фаворит - KeyValuePair

    Dictionary myDictionary = new Dictionary();
    // Populate your dictionary here
    
    foreach (KeyValuePair kvp in myDictionary)
    {
         // Do some interesting things
    }
    

    Вы также можете использовать ключи и коллекции значений

    ответ дан theo, с репутацией 3245, 26.09.2008
  • 22 рейтинг

    Я ценю, что на этот вопрос уже было много ответов, но я хотел добавить небольшое исследование.

    Итерация по словарю может быть довольно медленной по сравнению с итерацией по чему-то вроде массива. В моих тестах итерация по массиву заняла 0. 015003 секунды, тогда как итерация по словарю (с тем же количеством элементов) заняла 0. 0365073 секунд, это 2. В 4 раза больше! Хотя я видел гораздо большие различия. Для сравнения список был где-то посередине в 0. 00215043 секунд.

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

    Словари оптимизированы для поиска, поэтому, имея в виду, я создал два метода. Один просто делает foreach, другой перебирает ключи, затем смотрит вверх.

    public static string Normal(Dictionary dictionary)
    {
        string value;
        int count = 0;
        foreach (var kvp in dictionary)
        {
            value = kvp.Value;
            count++;
        }
    
        return "Normal";
    }
    

    Этот загружает ключи и перебирает их вместо этого (я также пытался вставить ключи в строку [], но разница была незначительной.

    public static string Keys(Dictionary dictionary)
    {
        string value;
        int count = 0;
        foreach (var key in dictionary.Keys)
        {
            value = dictionary[key];
            count++;
        }
    
        return "Keys";
    }
    

    В этом примере обычный тест foreach занял 0. 0310062 и ключи версии взяли 0. 2205441. Загрузка всех ключей и итерация по всем поискам явно намного медленнее!

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

    Вот метод RunTest, если он помогает вам визуализировать происходящее.

    private static string RunTest(T dictionary, Func function)
    {            
        DateTime start = DateTime.Now;
        string name = null;
        for (int i = 0; i < 10; i++)
        {
            name = function(dictionary);
        }
        DateTime end = DateTime.Now;
        var duration = end.Subtract(start);
        return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
    }
    

    Здесь нормальный прогон foreach занял 0. 2820564 секунды (примерно в десять раз дольше, чем на одну итерацию - как и следовало ожидать). Итерация по ключам заняла 2. 2249449 секунд.

    Отредактировано, чтобы добавить: Чтение некоторых других ответов заставило меня задуматься о том, что произойдет, если я воспользуюсь словарем вместо словаря. В этом примере массив принял 0. 0120024 секунд, список 0. 0185037 секунд и словарь 0. 0465093 секунд. Разумно ожидать, что тип данных влияет на то, насколько медленнее словарь.

    Каковы мои выводы ?

    • Избегайте итераций по словарю, если это возможно, они существенно медленнее, чем итерации по массиву с теми же данными в нем.
    • Если вы выбираете итерацию по словарю, не пытайтесь быть слишком умным, хотя медленнее вы можете сделать намного хуже, чем при использовании стандартного метода foreach.
    ответ дан Liath, с репутацией 6787, 30.07.2014
  • 9 рейтинг

    Вы предложили ниже повторить

    Dictionary myDictionary = new Dictionary();
    //Populate your dictionary here
    
    foreach (KeyValuePair kvp in myDictionary) {
        //Do some interesting things;
    }
    

    FYI, foreach не работает, если значение имеет тип объекта.

    ответ дан J Healy, с репутацией 1784, 28.10.2009
  • 8 рейтинг

    С .NET Framework 4.7 можно использовать разложение

    var fruits = new Dictionary();
    ...
    foreach (var (fruit, number) in fruits)
    {
        Console.WriteLine(fruit + ": " + number);
    }
    

    Чтобы этот код работал на более низких версиях C #, добавьте System.ValueTuple NuGet package и напишите куда-нибудь

    public static class MyExtensions
    {
        public static void Deconstruct(this KeyValuePair tuple,
            out T1 key, out T2 value)
        {
            key = tuple.Key;
            value = tuple.Value;
        }
    }
    
    ответ дан Pavel, с репутацией 780, 17.10.2017
  • 7 рейтинг

    Простейшая форма для повторения словаря:

    foreach(var item in myDictionary)
    { 
        Console.WriteLine(item.Key);
        Console.WriteLine(item.Value);
    }
    
    ответ дан Ron, с репутацией 864, 2.10.2016
  • 6 рейтинг

    Иногда, если вам нужно только перечислить значения, используйте коллекцию значений словаря:

    foreach(var value in dictionary.Values)
    {
        // do something with entry.Value only
    }
    

    Об этом сообщает этот пост, в котором говорится, что это самый быстрый метод: http: // alexpinsker. Blogspot. кк / 2010/02 / с-быстро путь к итерации-над. HTML

    ответ дан ender, с репутацией 337, 2.07.2014
  • 5 рейтинг

    Используя C # 7 , добавьте метод расширения в любой проект вашего решения:

    public static class IDictionaryExtensions
    {
        public static IEnumerable<(TKey, TValue)> Tuples(
            this IDictionary dict)
        {
            foreach (KeyValuePair kvp in dict)
                yield return (kvp.Key, kvp.Value);
        }
    }
    


    И использовать этот простой синтаксис

    foreach (var(id, value) in dict.Tuples())
    {
        // your code using 'id' and 'value'
    }
    


    Или этот, если вы предпочитаете

    foreach ((string id, object value) in dict.Tuples())
    {
        // your code using 'id' and 'value'
    }
    


    На месте традиционного

    foreach (KeyValuePair kvp in dict)
    {
        string id = kvp.Key;
        object value = kvp.Value;
    
        // your code using 'id' and 'value'
    }
    


    Метод расширения преобразует KeyValuePair вашего IDictionary в строго типизированный tuple, что позволяет вам использовать этот новый удобный синтаксис.

    Он преобразует -просто необходимые словарные записи в tuples, поэтому он НЕ преобразует весь словарь в tuples, поэтому никаких проблем с производительностью, связанных с этим.

    Существует только незначительная стоимость вызова метода расширения для создания tuple по сравнению с непосредственным использованием KeyValuePair, что не должно вызывать проблем, если вы все равно назначаете свойства KeyValuePair Key и Value новым переменным цикла.

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

    Проверьте это: Блог MSDN - новые функции в C # 7

    ответ дан sɐunıɔןɐqɐp, с репутацией 1270, 27.05.2018
  • 5 рейтинг

    Я нашел этот метод в документации для класса DictionaryBase на MSDN:

    foreach (DictionaryEntry de in myDictionary)
    {
         //Do some stuff with de.Value or de.Key
    }

    Это было единственное, что мне удалось правильно функционировать в классе, унаследованном от DictionaryBase.

    ответ дан J Healy, с репутацией 1784, 17.02.2009
  • 3 рейтинг

    Стандартный способ перебора словаря, согласно официальной документации на MSDN:

    foreach (DictionaryEntry entry in myDictionary)
    {
         //Read entry.Key and entry.Value here
    }
    
    ответ дан Nick, с репутацией 69, 28.07.2016
  • 3 рейтинг

    Я воспользуюсь преимуществом. NET 4. 0+ и предоставьте обновленный ответ на первоначально принятый:

    foreach(var entry in MyDic)
    {
        // do something with entry.Value or entry.Key
    }
    
    ответ дан yazanpro, с репутацией 1726, 1.10.2014
  • 2 рейтинг

    Если, скажем, вы хотите перебрать коллекцию значений по умолчанию, я думаю, что вы можете реализовать IEnumerable & lt; & gt ;, где T - это тип объекта значений в словаре, а "this" - это словарь.

    public new IEnumerator GetEnumerator()
    {
       return this.Values.GetEnumerator();
    }
    
    ответ дан J Healy, с репутацией 1784, 9.12.2008
  • 2 рейтинг

    Начиная с C # 7, вы можете деконструировать объекты в переменные. Я считаю, что это лучший способ перебора словаря.

    Пример:

    Создайте метод расширения для KeyValuePair, который его деконструирует:

    public static void Deconstruct(this KeyValuePair pair, out TKey, out TVal val)
    {
       key = pair.Key;
       val = pair.Value;
    }
    

    Выполните итерацию по любому Dictionary следующим образом

    // Dictionary can be of any types, just using 'int' and 'string' as examples.
    Dictionary dict = new Dictionary();
    
    // Deconstructor gets called here.
    foreach (var (key, value) in dict)
    {
       Console.WriteLine($"{key} : {value}");
    }
    
    ответ дан Domn Werner, с репутацией 149, 11.07.2018
  • 1 рейтинг

    Я написал расширение для цикла по словарю.

    public static class DictionaryExtension
    {
        public static void ForEach(this Dictionary dictionary, Action action) {
            foreach(KeyValuePair keyValue in dictionary) {
                action(keyValue.Key, keyValue.Value);
            }
        }
    }
    

    Тогда можно звонить

    myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));
    
    ответ дан Steven Delrue, с репутацией 131, 8.06.2018
  • 1 рейтинг
    var dictionary = new Dictionary
    {
        { "Key", 12 }
    };
    
    var aggregateObjectCollection = dictionary.Select(
        entry => new AggregateObject(entry.Key, entry.Value));
    
    ответ дан Pixar, с репутацией 351, 28.05.2015
  • 1 рейтинг

    Просто хотел добавить мои 2 цента, так как большинство ответов касаются цикла foreach. Пожалуйста, взгляните на следующий код:

    Dictionary myProductPrices = new Dictionary();
    
    //Add some entries to the dictionary
    
    myProductPrices.ToList().ForEach(kvP => 
    {
        kvP.Value *= 1.15;
        Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
    });
    

    Хотя это добавляет дополнительный вызов '. ToList () ', может быть небольшое улучшение производительности (как указано здесь foreach vs someList. Foreach () {} ), особенно при работе с большими словарями и параллельной работе это не вариант / не будет иметь никакого эффекта вообще.

    Также обратите внимание, что вы не сможете присвоить значения свойству «Значение» внутри цикла foreach. С другой стороны, вы также сможете манипулировать «ключом», что может привести к неприятностям во время выполнения.

    Если вы просто хотите «прочитать» ключи и значения, вы также можете использовать IEnumerable. Выбрать().

    var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
    
    ответ дан Alex, с репутацией 99, 16.09.2016
  • 0 рейтинг

    Словарь & lt; TKey, TValue & gt; Это универсальный класс коллекции в c #, в котором хранятся данные в формате значения ключа. Ключ должен быть уникальным, и он не может быть нулевым, тогда как значение может быть повторяющимся и нулевым. Поскольку каждый элемент в словаре рассматривается как KeyValuePair & lt; TKey, TValue & gt; структура, представляющая ключ и его значение. и, следовательно, мы должны взять тип элемента KeyValuePair & lt; TKey, TValue & GT; во время итерации элемента. Ниже приведен пример.

    Dictionary dict = new Dictionary();
    dict.Add(1,"One");
    dict.Add(2,"Two");
    dict.Add(3,"Three");
    
    foreach (KeyValuePair item in dict)
    {
        Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
    }
    
    ответ дан Sheo Dayal Singh, с репутацией 456, 16.04.2018
  • -1 рейтинг

    в дополнение к постам с самым высоким рейтингом, где есть обсуждение между использованием

    foreach(KeyValuePair entry in myDictionary)
    {
        // do something with entry.Value or entry.Key
    }
    

    или

    foreach(var entry in myDictionary)
    {
        // do something with entry.Value or entry.Key
    }
    

    наиболее полным является следующее, потому что вы можете видеть тип словаря из инициализации, kvp - это KeyValuePair

    var myDictionary = new Dictionary(x);//fill dictionary with x
    
    foreach(var kvp in myDictionary)//iterate over dictionary
    {
        // do something with kvp.Value or kvp.Key
    }
    
    ответ дан BigChief, с репутацией 791, 19.08.2018
  • -2 рейтинг

    Словари являются специальными списками, тогда как каждое значение в списке имеет ключ которая также является переменной. Хорошим примером словаря является телефонная книга.

       Dictionary phonebook = new Dictionary();
        phonebook.Add("Alex", 4154346543);
        phonebook["Jessica"] = 4159484588;
    

    Обратите внимание, что при определении словаря нам нужно предоставить общий определение с двумя типами - тип ключа и тип значения. В этом случае ключ является строкой, а значение является целым числом.

    Существует также два способа добавления одного значения в словарь: с помощью оператора скобок или с помощью метода Add.

    Чтобы проверить, есть ли в словаре определенный ключ, мы можем использовать метод ContainsKey:

    Dictionary phonebook = new Dictionary();
    phonebook.Add("Alex", 415434543);
    phonebook["Jessica"] = 415984588;
    
    if (phonebook.ContainsKey("Alex"))
    {
        Console.WriteLine("Alex's number is " + phonebook["Alex"]);
    }
    

    Чтобы удалить элемент из словаря, мы можем использовать метод Remove. Удаление элемента из словаря по его ключу - это быстро и очень эффективно. При удалении элемента из списка с использованием его значения процесс идет медленно и неэффективно, в отличие от функции удаления из словаря.

    Dictionary phonebook = new Dictionary();
    phonebook.Add("Alex", 415434543);
    phonebook["Jessica"] = 415984588;
    
    phonebook.Remove("Jessica");
    Console.WriteLine(phonebook.Count);
    
    ответ дан Amit Kumar Verma, с репутацией 162, 9.03.2018