Перечисляет ли перечислитель словаря <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.