Каков наилучший способ перебора словаря? - PullRequest
2264 голосов
/ 26 сентября 2008

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

Ответы [ 26 ]

3279 голосов
/ 26 сентября 2008
foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}
755 голосов
/ 26 сентября 2008

Если вы пытаетесь использовать универсальный словарь в 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 и выше, вы также можете использовать точный тип ваших ключей / значений здесь)

125 голосов
/ 10 марта 2011

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

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}
83 голосов
/ 26 сентября 2008

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

Из MSDN Dictionary(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 голосов
/ 10 августа 2015

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

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

С другой стороны, существует много способов перебора словаря в 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 предоставляет краткий синтаксис, который позволяет указывать порядок (и многое другое), например ::

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

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

46 голосов
/ 26 сентября 2008

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

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

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

35 голосов
/ 11 июня 2015

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

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});
25 голосов
/ 30 июля 2014

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

Итерация по словарю может быть довольно медленной по сравнению с итерацией по чему-то вроде массива. В моих тестах итерация по массиву занимала 0,015003 секунды, тогда как итерация по словарю (с тем же количеством элементов) занимала 0,0365073 секунды, что в 2,4 раза больше! Хотя я видел гораздо большие различия. Для сравнения, список был где-то посередине в 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.
25 голосов
/ 26 сентября 2008

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

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

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

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

14 голосов
/ 07 января 2019

C # 7.0 введено Деконструкторы и, если вы используете .NET Core 2.0 + Приложение, структура KeyValuePair<> уже включает Deconstruct() для вас. Так что вы можете сделать:

var dic = new Dictionary<int, string>() { { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
foreach (var (key, value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}
//Or
foreach (var (_, value) in dic) {
    Console.WriteLine($"Item [NO_ID] = {value}");
}
//Or
foreach ((int key, string value) in dic) {
    Console.WriteLine($"Item [{key}] = {value}");
}

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...