Возвращает ли перечислитель Dictionary<TKey, TValue> пары ключ-значение в том порядке, в котором они были добавлены?
Я понимаю, что словарь не является упорядоченной коллекцией и не должен зависеть от порядка вставки и поиска в словаре.
Однако вот что я заметил:
- Добавлено 20 пар ключевых значений в словарь
- Получил их, выполнив foreach(KeyValuePair...)
Порядок поиска был такой же, как порядок их добавления. Протестировано около 16 пар ключевых значений.
Это по замыслу?
7 ответов
По совпадению, хотя и предсказуемо. Вы абсолютно не должны полагаться на это. Обычно это происходит в простых ситуациях, но если вы начнете удалять элементы и заменять их чем-либо либо с тем же хеш-кодом, либо просто попадать в ту же корзину, этот элемент займет позицию оригинала, несмотря на то, что он был добавлен позже, чем другие,
Воспроизвести это относительно сложно, но мне удалось сделать это некоторое время назад по другому вопросу:
using System;
using System.Collections.Generic;
class Test
{
static void Main(string[] args)
{
var dict = new Dictionary<int, int>();
dict.Add(0, 0);
dict.Add(1, 1);
dict.Add(2, 2);
dict.Remove(0);
dict.Add(10, 10);
foreach (var entry in dict)
{
Console.WriteLine(entry.Key);
}
}
}
Результаты показывают 10, 1, 2, а не 1, 2, 10.
Обратите внимание, что даже если похоже, что текущее поведение будет всегда давать элементы в порядке вставки, если вы не выполняете никаких удалений, нет гарантии, что будущие реализации будут делать то же самое... так что даже в ограниченном случае, когда вы знаете, что выиграли ничего не удаляйте, пожалуйста, не полагайтесь на это.
Из MSDN:
Для целей перечисления каждый элемент в словаре рассматривается как
KeyValuePair<(Of <(TKey, TValue>)>)
структура, представляющая значение и его ключ. Порядок возврата товаров не определен.
[Акцент добавлен]
Если вы хотите перебрать словарь в фиксированном порядке, вы можете попробовать OrderedDictionary
Именно по замыслу Dictionary<TKey,TValue>
не является упорядоченной структурой, так как она предназначена в основном для доступа на основе ключей.
Если вам нужно получить элементы в определенном порядке, вы должны взглянуть на Sorted Dictionary<TKey, TValue>
, который занимает Comparer<T>
который будет использоваться для сортировки ключей в Sorted Dictionary<TKey, TValue>
,
Это по замыслу? Вероятно, этого не было в оригинальной.Net Framework 2.0, но теперь существует неявный контракт, что они будут упорядочены в том же порядке, что и добавленные, потому что изменение этого параметра приведет к поломке настолько большого количества кода, который зависит от поведения исходного универсального толковый словарь. Сравните с языком Go, где их карта преднамеренно возвращает случайный порядок, чтобы пользователи карт не полагались на любой порядок [1].
Любые улучшения или изменения, которые авторы делают в словаре<T,V>
должен был бы сохранить этот скрытый контракт.
[1] "После выпуска Go 1.0 среда выполнения имеет рандомизированный порядок итераций карты.", https://blog.golang.org/go-maps-in-action.
Я так не думаю, словарь не обеспечивает внутреннее упорядочение элементов внутри него. Если вам нужно сохранить порядок, используйте дополнительную структуру данных (массив или список) вместе со словарем.
Я считаю перечисление Dictionary<K,V>
возвратит ключи в том же порядке, в котором они были вставлены, если все ключи хешируются с одинаковым значением. Это потому что Dictionary<K,V>
Реализация использует хеш-код объекта ключа для вставки пар ключ / значение в сегменты, а значения (как правило) хранятся в сегментах в порядке их вставки. Если вы постоянно наблюдаете это поведение с вашими пользовательскими объектами, то, возможно, вы не (правильно) переопределили GetHashCode()
метод?