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

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

26.09.2008 18:20:06
Я удивлен, что есть много ответов на этот вопрос, наряду с одним проголосовавшим 923 раза .. (использует foreach ofcourse) .. Я бы поспорил или, по крайней мере, добавил, что если вам придется перебирать словарь, скорее всего, вы использовать его неправильно / ненадлежащим образом. Я должен был сделать этот комментарий, потому что я видел злоупотребления в словарях способами, которые ИМХО были неуместны ... Да, могут быть редкие обстоятельства, когда вы перебираете словарь, а не ищите, вот что это разработано для .. Пожалуйста, имейте это в виду, прежде чем задаться вопросом, как перебрать словарь.
Vikas Gupta 18.09.2014 06:52:28
@VikasGupta Что бы вы посоветовали для того, чтобы что-то сделать с набором пар ключ-значение, если вы не знаете, какими будут ключи?
nasch 26.02.2015 22:27:55
@displayName Если вы хотите что-то сделать с каждой парой ключ-значение, но у вас нет ссылки на ключи, которые можно использовать для поиска значений, вы бы перебирали словарь, верно? Я просто указывал, что бывают моменты, когда вы захотите это сделать, несмотря на утверждение Викаса о том, что это, как правило, неправильное использование.
nasch 28.10.2015 18:01:43
Сказать, что это неправильное использование, означает, что есть лучшая альтернатива. Что это за альтернатива?
Kyle Delaney 20.06.2017 21:13:00
VikasGupta не прав, я могу подтвердить, что после многих лет высокопроизводительного программирования на C # и C ++ в не теоретических сценариях. Действительно, часто бывают случаи, когда можно создать словарь, сохранить уникальные пары ключ-значение, а затем выполнить итерацию по этим значениям, которые, как доказано, имеют уникальные ключи в коллекции. Создание любых других коллекций - это действительно неэффективный и дорогостоящий способ избежать повторения словаря. Пожалуйста, предоставьте хорошую альтернативу в качестве ответа на вопрос, разъясняющий вашу точку зрения, иначе ваш комментарий будет довольно бессмысленным.
sɐunıɔןɐqɐp 1.08.2018 20:53:42
28 ОТВЕТОВ
РЕШЕНИЕ
foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}
3658
20.12.2017 23:14:01
Что делать, если я точно не знаю тип ключа / значения в словаре. Использование var entryлучше в этом случае, и, таким образом, я проголосовал за этот ответ на второй взгляд вместо вышеупомянутого.
Ozair Kafray 5.01.2016 07:32:50
Использование @OzairKafray, varкогда вы не знаете тип, обычно плохая практика.
Nate 25.01.2016 23:34:44
Этот ответ лучше, потому что Пабло по умолчанию не использовал ленивый кодер "var", который скрывает возвращаемый тип.
MonkeyWrench 17.05.2016 17:19:20
@MonkeyWrench: Мех. Visual Studio знает, что это за тип; все, что вам нужно сделать, это навести курсор на переменную, чтобы узнать.
Robert Harvey 9.12.2016 18:30:18
Насколько я понимаю, varработает только если тип известен во время компиляции. Если Visual Studio знает тип, то он также доступен для вас.
Kyle Delaney 21.09.2017 13:06:01

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

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

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

53
17.05.2018 15:59:56
Хм, не смущает ли название предмета "ценность"? Обычно вы используете синтаксис, такой как «value.Key» и «value.Value», который не очень понятен для тех, кто будет читать код, особенно если он не знаком с реализацией словаря .Net. ,
RenniePet 11.01.2014 12:09:04
@RenniePet kvpобычно используется для именования экземпляров KeyValuePair при Перебор словарей и связанных с ними структур данных: foreach(var kvp in myDictionary){....
mbx 9.03.2016 16:10:49

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

857
2.02.2015 19:19:26
функция var наиболее необходима для вашего первого блока кода :)
nawfal 1.11.2013 14:26:01
Я ценю, что этот ответ указывает на то, что вы можете перебирать ключи или значения явно.
Rotsiser Mho 13.01.2015 06:17:21
Мне не нравится использование var здесь. Учитывая, что это просто синтаксический сахар, зачем его здесь использовать? Когда кто-то пытается прочитать код, ему нужно будет переходить по коду, чтобы определить тип myDictionary(если, конечно, это не настоящее имя). Я думаю, что использование var хорошо, когда тип очевиден, например, var x = "some string"но когда он не очевиден сразу, я думаю, что ленивое кодирование вредит читателю / рецензенту кода
James Wierzba 25.01.2017 17:23:39
varследует использовать экономно, на мой взгляд. Особенно здесь, это не конструктивно: тип KeyValuePair, вероятно, имеет отношение к вопросу.
Sinjai 21.08.2017 16:21:44
varимеет уникальную цель, и я не верю, что это «синтаксический» сахар. Целенаправленное использование этого является подходящим подходом.
Joshua K 7.09.2018 18:43:45

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

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

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

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

26
12.04.2018 10:17:29

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

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

// 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);
}
96
24.06.2019 11:11:26

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

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}
1
9.12.2008 04:16:11

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

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

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

5
17.02.2009 23:51:39
Это похоже на использование не словарной версии словаря ... т.е. до .NET Framework 2.0.
joedotnot 26.04.2014 13:21:36
@ joed0tnot: это не универсальная версия, используемая для Hashtableобъектов
sɐunıɔןɐqɐp 1.08.2018 19:42:55

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

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

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

К вашему сведению, foreachне работает, если значение имеет тип объекта.

10
12.05.2010 16:01:15
Пожалуйста, уточните: foreachне будет работать, если какое значение имеет тип object? В противном случае это не имеет особого смысла.
Marc L. 29.12.2017 16:22:59

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

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}
157
4.07.2018 12:25:28
Чтобы использовать метод .ElementAt, помните: using System.Linq; Это не входит в FX. автоматически сгенерированные тестовые классы.
Tinia 24.11.2011 14:47:37
Это путь, если вы изменяете значения, связанные с ключами. В противном случае выдается исключение при изменении и использовании foreach ().
Mike de Klerk 3.04.2013 07:18:23
Не ElementAtявляется ли операция O (n)?
Arturo Torres Sánchez 7.02.2015 01:46:14
Этот ответ совершенно не заслуживает такого количества голосов. Словарь не имеет неявного порядка, поэтому использование .ElementAtв этом контексте может привести к незначительным ошибкам. Гораздо более серьезный вопрос Артуро выше. Вы будете повторять время словаря, dictionary.Count + 1приводящее к сложности O (n ^ 2) для операции, которая должна быть только O (n). Если вам действительно нужен индекс (в противном случае вы, вероятно, в первую очередь используете неправильный тип коллекции), вам следует dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})вместо этого выполнять итерацию, а не использовать ее .ElementAtвнутри цикла.
spender 2.03.2015 02:17:05
ElementAt - o (n) операция! Шутки в сторону? Это пример того, как вы не должны это делать. Эти много голосов?
Mukesh Adhvaryu 12.05.2016 22:14:44

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

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
2.07.2014 01:55:08
+1 для повышения производительности. Действительно, итерация по самому словарю включает некоторые издержки, если все, что вам нужно, это значения. Это происходит в основном из-за копирования значений или ссылок в структуры KeyValuePair.
Jaanus Varus 5.08.2015 10:25:26
К вашему сведению, последний тест в этой ссылке - это проверка не того: он измеряет итерацию по ключам, игнорируя значения, тогда как два предыдущих теста действительно используют это значение.
Crescent Fresh 13.07.2018 14:15:04

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

Итерация по словарю может быть довольно медленной по сравнению с итерацией по чему-то вроде массива. В моих тестах итерация по массиву занимала 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.
29
28.04.2018 12:22:57
Вы должны измерять что-то вроде StopWatch вместо DateTime: hanselman.com/blog/…
Even Mien 23.02.2015 19:26:09
Не могли бы вы описать ваш тестовый сценарий, сколько элементов в вашем словаре, как часто вы запускали свой сценарий для расчета среднего времени, ...
WiiMaxx 29.07.2015 08:57:13
Интересно, что вы получите разные результаты в зависимости от того, какие данные у вас есть в словаре. Выполняя итерацию по словарю, функция Enumerator должна пропускать много пустых слотов в словаре, что делает его медленнее, чем итерация по массиву. Если словарь заполнен, пустых слотов будет меньше, чем если он наполовину пуст.
Martin Brown 30.06.2016 08:36:25

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

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}
3
1.10.2014 23:17:52
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));
0
28.05.2015 15:00:10
В этом ответе должно быть больше обоснования / описания. Что AggregateObjectдобавить к KeyValuePair? Где находится «итерация», как было указано в вопросе?
Marc L. 29.12.2017 16:37:24
Select перебирает словарь и позволяет нам работать с каждым объектом. Это не так широко, как foreach, но я использовал это много. Действительно ли мой ответ заслуживает отрицательного ответа?
Pixar 2.06.2018 18:37:37
Нет, Select использует итерацию для получения результата, но не является итератором. Типы вещей, для которых используется iteration ( foreach) - особенно операции с побочными эффектами - выходят за рамки Linq, в том числе Select. Лямбда не будет работать, пока не aggregateObjectCollectionбудет фактически перечислена. Если этот ответ принимается за «первый путь» (т. Е. Используется перед прямой foreach), он поощряет плохие практики. В некоторых случаях могут быть полезны операции Linq перед итерацией словаря, но это не решает вопрос в том виде, в котором он задан.
Marc L. 4.06.2018 16:11:01

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

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});
37
11.06.2015 14:50:43
@WiiMaxx и более важно, если эти предметы НЕ зависят друг от друга
Mafii 23.09.2016 10:07:50

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

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

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

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

81
3.06.2019 12:28:39
Последний должен быть, .Valuesа не пункт выбора.
Mafii 23.09.2016 10:05:34
@Mafii Ты уверен? Значения, возвращаемые OrderBy, не относятся к типу KeyValuePair, у них нет Valueполя. Точный тип, который я вижу здесь IOrderedEnumerable<KeyValuePair<TKey, TValue>>. Возможно, вы имели в виду что-то еще? Можете ли вы написать полную строку, показывающую, что вы имеете в виду (и проверить это)?
Stéphane Gourichon 23.09.2016 14:30:16
Я думаю, что этот ответ содержит то, что я имею в виду: stackoverflow.com/a/141105/5962841, но поправьте меня, если я что-то
Mafii 23.09.2016 14:34:22
@Mafii Перечитайте весь мой ответ, объяснения между разделами кода говорят о контексте. Ответ, который вы упоминаете, похож на второй раздел кода в моем ответе (порядок не требуется). Там я просто написал, items.Valueкак вы предложили. В случае с четвертым разделом, который вы прокомментировали, Select()есть способ заставить foreachперечислять непосредственно значения в словаре вместо пар ключ-значение. Если вам как-то не нравится Select()в этом случае, вы можете предпочесть третий раздел кода. Смысл четвертого раздела - показать, что можно предварительно обработать коллекцию с помощью LINQ.
Stéphane Gourichon 23.09.2016 15:14:18
Если вы это сделаете, .Keys.Orderby()вы будете перебирать список ключей. Если это все, что вам нужно, хорошо. Если вам нужны значения, то в цикле вам придется запросить словарь по каждому ключу, чтобы получить значение. Во многих случаях это не будет иметь практического значения. В высокопроизводительном сценарии это будет. Как я писал в начале ответа: «Есть много способов (...), и нет лучшего пути. Это зависит от необходимости, а зачастую и от вкуса».
Stéphane Gourichon 23.09.2016 15:23:31

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

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}
3
28.07.2016 10:58:55

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

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

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

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

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
1
23.05.2017 12:34:47
Копирование всей коллекции без всякой причины не улучшит производительность. Это значительно замедлит код, а также удвоит объем памяти кода, который практически не потребляет дополнительной памяти.
Servy 16.09.2016 16:08:11
Я избегаю побочного эффекта «List.ForEach»: усиливает foreachвидимость побочного эффекта там, где он есть.
user2864740 28.03.2017 22:30:45

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

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}
9
13.03.2017 15:35:17

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

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

Чтобы этот код работал на более низких версиях C #, добавьте 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;
    }
}
13
17.10.2017 15:18:55
Это неверно .NET 4.7 просто ValueTupleвстроен. Он доступен как пакет nuget для более ранних версий. Что еще более важно, C # 7.0+ необходим для того, Deconstructчтобы метод работал в качестве деконструктора var (fruit, number) in fruits.
David Arno 18.10.2017 11:58:34

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

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

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

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

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

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

if (phonebook.ContainsKey("Alex"))
{
    Console.WriteLine("Alex's number is " + phonebook["Alex"]);
}

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

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

phonebook.Remove("Jessica");
Console.WriteLine(phonebook.Count);
-5
15.03.2018 14:19:14
Ничто из этого не отвечает на вопрос: каков наилучший способ перебора словаря?
Sam W 19.04.2019 14:30:22

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

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");

foreach (KeyValuePair<int, string> item in dict)
{
    Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
0
16.04.2018 11:25:37

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

public static class IDictionaryExtensions
{
    public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
        this IDictionary<TKey, TValue> dict)
    {
        foreach (KeyValuePair<TKey, TValue> 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<string, object> kvp in dict)
{
    string id = kvp.Key;
    object value = kvp.Value;

    // your code using 'id' and 'value'
}


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

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

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

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

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

9
1.08.2018 20:38:35
В чем причина предпочтения «удобных» кортежей парам «ключ-значение»? Я не вижу здесь выгоды. Ваш кортеж содержит ключ и значение, как и пара ключ-значение.
Maarten 10.09.2018 12:57:33
Привет, Мартен, спасибо за твой вопрос. Основным преимуществом является читаемость кода без дополнительных усилий программирования. С KeyValuePair нужно всегда использовать форму kvp.Keyи kvp.Valueиспользовать соответственно ключ и значение. С помощью кортежей вы можете гибко называть ключ и значение по своему желанию, не используя дополнительные объявления переменных внутри блока foreach. Например, вы можете назвать свой ключ как factoryName, а значение как models, что особенно полезно, когда вы получаете вложенные циклы (словари словарей): обслуживание кода становится намного проще. Просто попробуйте! ;-)
sɐunıɔןɐqɐp 10.09.2018 13:49:21

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

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

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

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));
2
8.06.2018 07:07:02
Вы определили ForEachметод, в котором у вас есть foreach (...) { }... Кажется ненужным.
Maarten 26.03.2019 13:51:35

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

Пример:

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

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

Выполните итерацию по любому Dictionary<TKey, TVal>из следующих способов

// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();

// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
   Console.WriteLine($"{key} : {value}");
}
13
3.10.2019 09:39:00

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

foreach(KeyValuePair<string, string> 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<string, string>(x);//fill dictionary with x

foreach(var kvp in myDictionary)//iterate over dictionary
{
    // do something with kvp.Value or kvp.Key
}
-3
19.08.2018 20:50:39
Создание и копирование второго словаря не является допустимым решением для удобочитаемости кода. На самом деле, я бы сказал, что это усложнит понимание кода, потому что теперь вы должны спросить себя: «Почему последний парень создал второй словарь?» Если вы хотите быть более многословным, просто используйте первый вариант.
Matthew Goulart 6.09.2018 19:23:40
Я просто хотел показать вам, что когда decl dict прежде для каждого, использование в foreach ясно из декларации
BigChief 8.09.2018 09:03:50

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

введите описание изображения здесь

33
7.01.2019 20:30:48
Если вы используете .NET Framework, который по крайней мере до 4.7.2 не имеет деконструкции на KeyValuePair, попробуйте это:foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
nwsmith 26.04.2019 11:58:34

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

    public static void ForEach<T, U>(this Dictionary<T, U> d, Action<KeyValuePair<T, U>> a)
    {
        foreach (KeyValuePair<T, U> p in d) { a(p); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.KeyCollection k, Action<T> a)
    {
        foreach (T t in k) { a(t); }
    }

    public static void ForEach<T, U>(this Dictionary<T, U>.ValueCollection v, Action<U> a)
    {
        foreach (U u in v) { a(u); }
    }

Таким образом, я могу написать код так:

myDictionary.ForEach(pair => Console.Write($"key: {pair.Key}, value: {pair.Value}"));
myDictionary.Keys.ForEach(key => Console.Write(key););
myDictionary.Values.ForEach(value => Console.Write(value););
5
14.06.2019 18:06:18

foreachсамый быстрый и если вы только перебираете ___.Values, он также быстрее

введите описание изображения здесь

4
26.11.2019 14:56:43