Возвращает ли перечислитель 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() метод?

Другие вопросы по тегам