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

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

1677
задан Jake Stewart 26 сент. '08 в 21:20
источник поделиться
20 ответов
foreach(KeyValuePair<string, string> entry in myDic)
{
    // do something with entry.Value or entry.Key
}
2547
ответ дан Pablo Fernandez 26 сент. '08 в 21:22
источник поделиться

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

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 является необязательной функцией С# 3.0 и выше, вы также можете использовать точный тип своих ключей/значений здесь)

528
ответ дан Jacob 26 сент. '08 в 21:22
источник поделиться

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

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}
98
ответ дан Maurício Fedatto 10 марта '11 в 23:44
источник поделиться

В зависимости от того, находитесь ли вы за клавишами или значениями...

Из MSDN Словарь < (Of < (TKey, TValue > ) > ) Описание класса:

// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
    Console.WriteLine("Key = {0}, Value = {1}", 
        kvp.Key, kvp.Value);
}

// To get the values alone, use the Values property.
Dictionary<string, string>.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<string, string>.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);
}
71
ответ дан J Healy 26 сент. '08 в 21:27
источник поделиться

Как правило, запрос "наилучшего пути" без конкретного контекста - это вопрос о том, какой лучший цвет.

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

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

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

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

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

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

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

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

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

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

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

48
ответ дан Stéphane Gourichon 10 авг. '15 в 14:15
источник поделиться

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

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

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

30
ответ дан George Mauer 26 сент. '08 в 21:22
источник поделиться

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

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

Foreach (KeyValuePair<string,object> kvp in myDictionary)
{
     //Do some interesting things;
}

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

21
ответ дан theo 26 сент. '08 в 21:22
источник поделиться

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

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});
19
ответ дан Onur 11 июня '15 в 16:32
источник поделиться

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

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

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

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

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

        return "Normal";
    }

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

    public static string Keys(Dictionary<string, string> 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>(T dictionary, Func<T, string> 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.
17
ответ дан Liath 30 июля '14 в 13:54
источник поделиться

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

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary) {
    //Do some interesting things;
}

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

9
ответ дан Khushi 28 окт. '09 в 23:49
источник поделиться

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

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}
8
ответ дан Ron 02 окт. '16 в 7:00
источник поделиться

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

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

Сообщается этим сообщением, в котором говорится, что это самый быстрый метод: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html

6
ответ дан ender 02 июля '14 в 4:55
источник поделиться

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

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

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

5
ответ дан Zannjaminderson 18 февр. '09 в 2:51
источник поделиться

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

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}
3
ответ дан Nick 28 июля '16 в 13:58
источник поделиться

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

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}
3
ответ дан yazanpro 02 окт. '14 в 2:17
источник поделиться

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

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}
2
ответ дан mzirino 09 дек. '08 в 7:16
источник поделиться

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

Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();

//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() {}), espacially при работе с большими словарями и параллельном запуске не является параметром/не будет иметь никакого эффекта вообще.

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

Когда вы просто хотите "читать" клавиши и значения, вы также можете использовать IEnumerable.Select().

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
1
ответ дан Alex 16 сент. '16 в 19:03
источник поделиться
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));
0
ответ дан Pixar 28 мая '15 в 18:00
источник поделиться

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

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

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

public static class MyExtensions
{
    public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
        out T1 key, out T2 value)
    {
        key = tuple.Key;
        value = tuple.Value;
    }
}
0
ответ дан Pavel 17 окт. '17 в 18:18
источник поделиться

Не стандартный способ, но работающий:

Dictionary<string, int> dict = new Dictionary<string, int>
{
    {"Foo", 1 },
    {"Bar", 2 }
};

dict.Select(kvp => { Console.WriteLine(kvp.Key + " - " + kvp.Value.ToString()); return kvp; }).Count();
0
ответ дан w.b 05 июля '15 в 16:36
источник поделиться

Другие вопросы по меткам