Я видел несколько разных способов перебора словаря в C #. Есть ли стандартный способ?
Я видел несколько разных способов перебора словаря в C #. Есть ли стандартный способ?
foreach(KeyValuePair entry in myDictionary)
{
// do something with entry.Value or entry.Key
}
Если вы пытаетесь использовать универсальный словарь в 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 и выше, вы также можете использовать точный тип ваших ключей / значений здесь)
В некоторых случаях вам может понадобиться счетчик, который может быть предоставлен реализацией цикла for. Для этого LINQ предоставляет ElementAt
, что позволяет следующее:
for (int index = 0; index < dictionary.Count; index++) {
var item = dictionary.ElementAt(index);
var itemKey = item.Key;
var itemValue = item.Value;
}
Зависит от того, хотите ли вы получить ключи или значения. , ,
Из 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);
}
Обычно спрашивать «лучший способ» без определенного контекста - это все равно, что спрашивать, какой цвет лучше.
С одной стороны, есть много цветов и нет лучшего цвета. Это зависит от необходимости и часто от вкуса тоже.
С другой стороны, существует много способов перебора словаря в 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)
}
Есть много других реальных вариантов использования, которые вы можете сделать из этих примеров. Если вам не нужен конкретный заказ, просто придерживайтесь «самого простого способа» (см. Выше)!
Я бы сказал, что foreach - это стандартный способ, хотя он, очевидно, зависит от того, что вы ищете.
foreach(var kvp in my_dictionary) {
...
}
Это то, что вы ищете?
Вы также можете попробовать это в больших словарях для многопоточной обработки.
dictionary
.AsParallel()
.ForAll(pair =>
{
// Process pair.Key and pair.Value here
});
Есть много вариантов. Мой личный фаворит - KeyValuePair
Dictionary myDictionary = new Dictionary();
// Populate your dictionary here
foreach (KeyValuePair kvp in myDictionary)
{
// Do some interesting things
}
Вы также можете использовать ключи и коллекции значений
Я ценю, что на этот вопрос уже было много ответов, но я хотел добавить небольшое исследование.
Итерация по словарю может быть довольно медленной по сравнению с итерацией по чему-то вроде массива. В моих тестах итерация по массиву заняла 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 секунд. Разумно ожидать, что тип данных влияет на то, насколько медленнее словарь.
Каковы мои выводы ?
Вы предложили ниже повторить
Dictionary myDictionary = new Dictionary();
//Populate your dictionary here
foreach (KeyValuePair kvp in myDictionary) {
//Do some interesting things;
}
FYI, foreach
не работает, если значение имеет тип объекта.
С .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;
}
}
Простейшая форма для повторения словаря:
foreach(var item in myDictionary)
{
Console.WriteLine(item.Key);
Console.WriteLine(item.Value);
}
Иногда, если вам нужно только перечислить значения, используйте коллекцию значений словаря:
foreach(var value in dictionary.Values)
{
// do something with entry.Value only
}
Об этом сообщает этот пост, в котором говорится, что это самый быстрый метод: http: // alexpinsker. Blogspot. кк / 2010/02 / с-быстро путь к итерации-над. HTML
Используя 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
Я нашел этот метод в документации для класса DictionaryBase на MSDN:
foreach (DictionaryEntry de in myDictionary)
{
//Do some stuff with de.Value or de.Key
}
Это было единственное, что мне удалось правильно функционировать в классе, унаследованном от DictionaryBase.
Стандартный способ перебора словаря, согласно официальной документации на MSDN:
foreach (DictionaryEntry entry in myDictionary)
{
//Read entry.Key and entry.Value here
}
Я воспользуюсь преимуществом. NET 4. 0+ и предоставьте обновленный ответ на первоначально принятый:
foreach(var entry in MyDic)
{
// do something with entry.Value or entry.Key
}
Если, скажем, вы хотите перебрать коллекцию значений по умолчанию, я думаю, что вы можете реализовать IEnumerable & lt; & gt ;, где T - это тип объекта значений в словаре, а "this" - это словарь.
public new IEnumerator GetEnumerator()
{
return this.Values.GetEnumerator();
}
Начиная с 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}");
}
Я написал расширение для цикла по словарю.
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));
var dictionary = new Dictionary
{
{ "Key", 12 }
};
var aggregateObjectCollection = dictionary.Select(
entry => new AggregateObject(entry.Key, entry.Value));
Просто хотел добавить мои 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 } );
Словарь & 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);
}
в дополнение к постам с самым высоким рейтингом, где есть обсуждение между использованием
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
}
Словари являются специальными списками, тогда как каждое значение в списке имеет ключ которая также является переменной. Хорошим примером словаря является телефонная книга.
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);