Я видел несколько разных способов перебора словаря в C #. Есть ли стандартный способ?
c#
dictionary
loops
Джейк Стюарт
источник
источник
Ответы:
источник
var entry
лучше в этом случае, и, таким образом, я проголосовал за этот ответ на второй взгляд вместо вышеупомянутого.var
когда вы не знаете тип, обычно плохая практика.var
работает только если тип известен во время компиляции. Если Visual Studio знает тип, то он также доступен для вас.Если вы пытаетесь использовать универсальный словарь в C #, как если бы вы использовали ассоциативный массив на другом языке:
Или, если вам нужно только перебрать коллекцию ключей, используйте
И, наконец, если вас интересуют только значения:
(Обратите внимание, что
var
ключевое слово является дополнительной функцией C # 3.0 и выше, вы также можете использовать точный тип ваших ключей / значений здесь)источник
myDictionary
(если, конечно, это не настоящее имя). Я думаю, что использование var хорошо, когда тип очевиден, например,var x = "some string"
но когда он не очевиден сразу, я думаю, что ленивое кодирование вредит читателю / рецензенту кодаvar
следует использовать экономно, по моему мнению. Особенно здесь, это не конструктивно: типKeyValuePair
, вероятно, имеет отношение к вопросу.var
имеет уникальную цель, и я не верю, что это «синтаксический» сахар. Целенаправленное использование является подходящим подходом.В некоторых случаях вам может понадобиться счетчик, который может быть предоставлен реализацией цикла for. Для этого LINQ предоставляет
ElementAt
следующее:источник
ElementAt
является ли операция O (n)?.ElementAt
в этом контексте может привести к незначительным ошибкам. Гораздо более серьезный вопрос Артуро выше. Вы будете повторять время словаря,dictionary.Count + 1
приводящее к сложности O (n ^ 2) для операции, которая должна быть только O (n). Если вам действительно нужен индекс (в противном случае вы, вероятно, в первую очередь используете неправильный тип коллекции), вам следуетdictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value})
вместо этого выполнять итерацию, а не использовать ее.ElementAt
внутри цикла.Зависит от того, хотите ли вы получить ключи или значения ...
Из
Dictionary(TKey, TValue)
описания класса MSDN :источник
Как правило, спрашивать «лучший способ» без определенного контекста - это все равно, что спрашивать, какой цвет лучше ?
С одной стороны, есть много цветов и нет лучшего цвета. Это зависит от необходимости и часто от вкуса тоже.
С другой стороны, есть много способов перебора словаря в C #, и лучшего способа нет. Это зависит от необходимости и часто от вкуса тоже.
Самый простой способ
Если вам нужно только значение (позволяет назвать его
item
, более читабельным, чемkvp.Value
).Если вам нужен определенный порядок сортировки
Как правило, новички удивляются порядку перечисления словаря.
LINQ предоставляет краткий синтаксис, который позволяет указывать порядок (и многое другое), например:
Опять же, вам может понадобиться только значение. LINQ также предоставляет краткое решение для:
item
, более читабельно, чемkvp.Value
)Вот:
Из этих примеров можно сделать гораздо больше реальных примеров использования. Если вам не нужен конкретный заказ, просто придерживайтесь «самого простого способа» (см. Выше)!
источник
.Values
а не пункт выбора.Value
поля. Точный тип, который я вижу здесьIOrderedEnumerable<KeyValuePair<TKey, TValue>>
. Возможно, вы имели в виду что-то еще? Можете ли вы написать полную строку, показывающую, что вы имеете в виду (и проверить это)?items.Value
как вы предложили. В случае с четвертым разделом, который вы прокомментировали,Select()
есть способ заставитьforeach
перечислять непосредственно значения в словаре вместо пар ключ-значение. Если вам как-то не нравитсяSelect()
в этом случае, вы можете предпочесть третий раздел кода. Смысл четвертого раздела - показать, что можно предварительно обработать коллекцию с помощью LINQ..Keys.Orderby()
вы будете перебирать список ключей. Если это все, что вам нужно, хорошо. Если вам нужны значения, то в цикле вам придется запросить словарь по каждому ключу, чтобы получить значение. Во многих случаях это не будет иметь практического значения. В высокопроизводительном сценарии это будет. Как я написал в начале ответа: «Есть много способов (...), и нет лучшего пути. Это зависит от необходимости, а зачастую и от вкуса».Я бы сказал, что foreach является стандартным способом, хотя он, очевидно, зависит от того, что вы ищете
Это то, что вы ищете?
источник
kvp
обычно используется для именования экземпляров KeyValuePair при Перебор словарей и связанных с ними структур данных:foreach(var kvp in myDictionary){...
.Вы также можете попробовать это в больших словарях для многопоточной обработки.
источник
C # 7.0 представил деконструкторы, и если вы используете приложение .NET Core 2.0+ , структура
KeyValuePair<>
уже включает в себяDeconstruct()
для вас. Так что вы можете сделать:источник
foreach (var (key, value) in dic.Select(x => (x.Key, x.Value)))
Я ценю, что у этого вопроса уже было много ответов, но я хотел добавить небольшое исследование.
Итерация по словарю может быть довольно медленной по сравнению с итерацией по чему-то вроде массива. В моих тестах итерация по массиву занимала 0,015003 секунды, тогда как итерация по словарю (с тем же количеством элементов) занимала 0,0365073 секунды, что в 2,4 раза больше! Хотя я видел гораздо большие различия. Для сравнения, список был где-то между 0,00215043 секундами.
Однако это все равно что сравнивать яблоки и апельсины. Я хочу сказать, что перебор словарей происходит медленно.
Словари оптимизированы для поиска, поэтому, имея в виду, я создал два метода. Один просто делает foreach, другой перебирает ключи, затем смотрит вверх.
Этот загружает ключи и перебирает их (я также пытался вытянуть ключи в строку [], но разница была незначительной.
В этом примере обычный тест foreach занял 0.0310062, а версия ключей - 0.2205441. Загрузка всех ключей и перебор всех поисков явно медленнее!
Для финального теста я выполнил свою итерацию десять раз, чтобы увидеть, есть ли какие-либо преимущества в использовании ключей здесь (к этому моменту мне было просто любопытно):
Вот метод RunTest, если он помогает вам визуализировать происходящее.
Здесь обычный цикл foreach занимал 0,2820564 секунды (примерно в десять раз дольше, чем одна итерация - как и следовало ожидать). Итерация по клавишам заняла 2,2249449 секунд.
Отредактировано, чтобы добавить: Чтение некоторых других ответов заставило меня задуматься, что произойдет, если я воспользуюсь словарем вместо словаря. В этом примере массив занял 0,0120024 секунды, список 0,0185037 секунд и словарь 0,0465093 секунд. Разумно ожидать, что тип данных влияет на то, насколько медленнее словарь.
Каковы мои выводы ?
источник
Есть много вариантов. Мой личный фаворит - KeyValuePair
Вы также можете использовать ключи и коллекции значений
источник
С
.NET Framework 4.7
одним можно использовать разложениеЧтобы этот код работал на более низких версиях C #, добавьте
System.ValueTuple NuGet package
и напишите куда-нибудьисточник
ValueTuple
встроен. Он доступен как пакет nuget для более ранних версий. Что еще более важно, C # 7.0+ необходим для того,Deconstruct
чтобы метод работал в качестве деконструктораvar (fruit, number) in fruits
.Начиная с C # 7, вы можете деконструировать объекты в переменные. Я считаю, что это лучший способ перебора словаря.
Пример:
Создайте метод расширения,
KeyValuePair<TKey, TVal>
который деконструирует его:Переберите любой
Dictionary<TKey, TVal>
из следующих способовисточник
Вы предложили ниже, чтобы повторить
К вашему сведению,
foreach
не работает, если значение имеет тип объекта.источник
foreach
не будет работать, если какое значение имеет типobject
? В противном случае это не имеет особого смысла.Простейшая форма для перебора словаря:
источник
Используя C # 7 , добавьте этот метод расширения в любой проект вашего решения:
И используйте этот простой синтаксис
Или этот, если вы предпочитаете
Вместо традиционного
Метод расширения преобразует
KeyValuePair
вашIDictionary<TKey, TValue>
код в строго типизированныйtuple
, что позволяет вам использовать этот новый удобный синтаксис.Он преобразует -просто необходимые словарные записи в
tuples
, поэтому он НЕ преобразует весь словарь вtuples
, поэтому никаких проблем с производительностью, связанных с этим.Существует только незначительная стоимость вызова метода расширения для создания
tuple
по сравнению с использованиемKeyValuePair
напрямую, что не должно быть проблемой, если вы присваиваетеKeyValuePair
свойстваKey
иValue
любом случае новым переменным цикла.На практике этот новый синтаксис очень хорошо подходит для большинства случаев, за исключением сценариев со сверхвысокой производительностью низкого уровня, когда у вас все еще есть возможность просто не использовать его в этом конкретном месте.
Проверьте это: Блог MSDN - Новые функции в C # 7
источник
kvp.Key
иkvp.Value
использовать соответственно ключ и значение. С помощью кортежей вы можете гибко называть ключ и значение по своему усмотрению, не используя дальнейшие объявления переменных внутри блока foreach. Например, вы можете назвать свой ключ какfactoryName
, а значение какmodels
, что особенно полезно, когда вы получаете вложенные циклы (словари словарей): обслуживание кода становится намного проще. Просто попробуйте! ;-)Я знаю, что это очень старый вопрос, но я создал несколько методов расширения, которые могут быть полезны:
Таким образом, я могу написать код так:
источник
Иногда, если вам нужно только перечислить значения, используйте коллекцию значений словаря:
Об этом сообщает этот пост, в котором говорится, что это самый быстрый метод: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html
источник
Я нашел этот метод в документации для класса DictionaryBase на MSDN:
Это было единственное, что мне удалось правильно функционировать в классе, унаследованном от DictionaryBase.
источник
Hashtable
объектовforeach
самый быстрый и если вы только перебираете___.Values
, он также быстрееисточник
ContainsKey()
вfor
версии? Это добавляет дополнительные издержки, которых нет в коде, с которым вы сравниваете.TryGetValue()
существует, чтобы заменить этот точный шаблон "если ключ существует, получить элемент с ключом". Кроме того, еслиdict
содержит непрерывный диапазон целых чисел от0
доdictCount - 1
, вы знаете, что индексатор не может выйти из строя; в противном случаеdict.Keys
это то , что вы должны повторять. В любом случае, нетContainsKey()
/TryGetValue()
нужно. Наконец, пожалуйста, не размещайте скриншоты кода.Я воспользуюсь преимуществами .NET 4.0+ и предоставлю обновленный ответ на изначально принятый:
источник
Стандартный способ перебора словаря, согласно официальной документации на MSDN:
источник
Я написал расширение для цикла над словарем.
Тогда вы можете позвонить
источник
ForEach
метод, в котором у вас естьforeach (...) { }
... Кажется ненужным.Если, скажем, вы хотите перебрать коллекцию значений по умолчанию, я полагаю, что вы можете реализовать IEnumerable <>, где T - это тип объекта значений в словаре, а «this» - словарь.
источник
Как уже указывалось на этот ответ ,
KeyValuePair<TKey, TValue>
реализуетDeconstruct
метод, начиная с .NET Core 2.0, .NET Standard 2.1 и .NET Framework 5.0 (предварительный просмотр).При этом можно перебирать словарь в
KeyValuePair
произвольной форме:источник
источник
AggregateObject
добавить кKeyValuePair
? Где находится «итерация», как было указано в вопросе?foreach
, но я использовал это много. Действительно ли мой ответ заслуживает отрицательного ответа?Select
использует итерацию для получения результата, но не является итератором. Типы вещей, для которых используется iteration (foreach
), особенно операции с побочными эффектами, выходят за рамки Linq, в том числеSelect
. Лямбда не будет работать, пока неaggregateObjectCollection
будет фактически перечислена. Если этот ответ принимается за «первый путь» (т. Е. Используется перед прямойforeach
), он поощряет плохие практики. В некоторых случаях могут быть полезны операции Linq перед итерацией словаря, но они не решают вопрос в том виде, в котором он задан.Просто хотел добавить свои 2 цента, так как большинство ответов касаются цикла foreach. Пожалуйста, взгляните на следующий код:
Хотя это добавляет дополнительный вызов .ToList (), может быть небольшое улучшение производительности (как указано здесь foreach против someList.Foreach () {} ), особенно при работе с большими словарями и параллельной работе нет опция / не будет иметь никакого эффекта вообще.
Также обратите внимание, что вы не сможете присваивать значения свойству Value внутри цикла foreach. С другой стороны, вы также сможете манипулировать «ключом», что может привести к проблемам во время выполнения.
Если вы просто хотите «прочитать» ключи и значения, вы также можете использовать IEnumerable.Select ().
источник
foreach
видимость побочных эффектов там, где они есть.Dictionary <TKey, TValue> Это универсальный класс коллекции в c #, в котором хранятся данные в формате значения ключа. Ключ должен быть уникальным и не может быть нулевым, в то время как значение может быть дублированным и нулевым. Поскольку каждый элемент в словаре рассматривается как структура KeyValuePair <TKey, TValue>, представляющая ключ и его значение. и, следовательно, мы должны взять тип элемента KeyValuePair <TKey, TValue> во время итерации элемента. Ниже приведен пример.
источник
Если вы хотите использовать для цикла, вы можете сделать это:
источник
foreach
цикл, и худшая производительность, потому что онnew List<string>(dictionary.Keys)
будет повторяться ещеdictionary.Count
раз, прежде чем у вас появится возможность повторить его самостоятельно. Оставляя в стороне, что просьба о «лучшем способе» субъективна, я не понимаю, как это можно квалифицировать как «наилучший» или «стандартный способ», который ищет вопрос. Чтобы «Если вы хотите использовать для цикла ...», я бы ответил « Не используйтеfor
цикл».foreach (var pair in dictionary.ToArray()) { }
. Тем не менее, я думаю, что было бы хорошо разъяснить в ответе конкретные сценарии, в которых можно использовать этот код, и последствия этого.просто с linq
источник
ToList()
потому чтоForEach()
он определен только вList<>
классе, но зачем все это, а не простоforeach (var pair in dict) { }
? Я бы сказал, что это еще проще и не имеет таких же последствий для памяти и производительности. Это точное решение уже было предложено в этом ответе от 3,5 лет назад, во всяком случае.в дополнение к постам с самым высоким рейтингом, где есть обсуждение между использованием
или
наиболее полным является следующее, потому что вы можете видеть тип словаря из инициализации, kvp - KeyValuePair
источник