Перечисляет ли перечислитель словаря <TKey, TValue> пары ключевых значений в том порядке, в котором они были добавлены?

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

Однако это то, что я заметил:

  • Добавлены 20 ключевых значений в словарь
  • Получил их, выполнив foreach (KeyValuePair...)

Порядок поиска был таким же, как и порядок, в котором они были добавлены. Протестировано около 16 пар ключей.

Это по дизайну?

Ответ 1

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

Это относительно нереально воспроизвести это, но мне удалось сделать это некоторое время назад для другого вопроса:

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.

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

Ответ 2

От MSDN:

Для целей перечисления каждый элемент в словаре рассматривается как структура KeyValuePair<(Of <(TKey, TValue>)>), представляющая значение и его ключ. Порядок возврата элементов undefined.

[Акцент добавлен]

Ответ 3

Если вы хотите итерации через словарь в фиксированном порядке, вы можете попробовать OrderedDictionary

Ответ 4

По идее, что Dictionary<TKey,TValue> не является упорядоченной структурой, поскольку предполагается, что он будет использоваться в основном больше для ключевых доступ.

Если вам нужно получить элементы в определенном порядке, вы должны взглянуть на Sorted Dictionary<TKey, TValue>, который принимает Comparer<T>, который будет использоваться для сортировки ключей в Sorted Dictionary<TKey, TValue>.

Ответ 5

Я так не думаю, что словарь не предоставляет внутренний порядок элементов внутри него. Если вам нужно сохранить порядок, используйте дополнительную структуру данных (массив или список) вместе со словарем.

Ответ 6

Я считаю, что перечисление Dictionary<K,V> вернет ключи в том же порядке, в который они были вставлены , если все хэши ключей имеют одно и то же значение. Это связано с тем, что реализация Dictionary<K,V> использует хэш-код ключевого объекта для вставки пар ключ/значение в ведра, а значения (обычно) хранятся в корзинах в том порядке, в котором они вставлены. Если вы последовательно видите это поведение с вашими определяемыми пользователем объектами, то, возможно, вы (правильно) не переопределили метод GetHashCode()?

Ответ 7

Это по дизайну? Вероятно, это было не в исходном.Net Framework 2.0, но теперь есть неявный контракт, который будет упорядочен в том же порядке, что и добавленный, потому что для изменения это приведет к разрыву столь большого количества кода, который опирается на поведение исходного общего Словарь. Сравните с языком Go, где их карта намеренно возвращает случайный порядок, чтобы пользователи карт не полагались на какое-либо упорядочение [1].

Любые улучшения или изменения, внесенные разработчиками фреймворка в словарь <T,V> должны были бы поддерживать этот неявный контракт.

[1] "Начиная с выпуска Go 1.0, время выполнения имеет рандомизированный порядок итерации карты". Https://blog.golang.org/go-maps-in-action.