При перечислении SortedDictionary возвращает KeyValuePairs в ожидаемом порядке? - PullRequest
8 голосов
/ 23 апреля 2011

Когда у меня SortedDictionary<TK, TV> в .NET и я хочу перечислить его как ICollection<KeyValuePair<TK, TV>>, он перечисляет в ожидаемом порядке?

То есть KeyValuePair<TK, TV> с наименьшим ключом возвращается первым, затем следует KeyValuePair<TK, TV> с вторым наименьшим ключом и т. Д .?

Примечание: будет принят только ответ, зарезервированный по ссылке.

Ответы [ 3 ]

10 голосов
/ 23 апреля 2011

Из ссылки для GetEnumerator:

"Словарь поддерживается в отсортированном порядке с использованием внутреннего дерева. Каждый новый элемент располагается в правильном положении сортировки, а дерево настраивается для поддержания порядка сортировки при удалении элемента. При перечислении порядок сортировки поддерживается. "

В частности: «При перечислении порядок сортировки сохраняется.»

3 голосов
/ 23 апреля 2011

Да, определенно, хотя вам будет очень трудно найти документацию, которая разъясняет это точно .

Хотя документация для каждой из четырех GetEnumerator перегрузок этого типа делает смутные заявления о возвращении «перечислителя, который перебирает коллекцию», вполне очевидно, что они должны создавать эквивалентные (отсортированные по ключу) последовательности; помните, что сортированный словарь предназначен для «представления набора пар ключ / значение, отсортированных по ключу». Было бы весьма не интуитивно понятным и запутанным для пользователей, если бы коллекция вела себя совершенно иначе (т.е. с другим порядком перечисления) между циклом foreach и запросом LINQ to Objects, например.

Лучшее, что я могу сделать, - предоставить вам реализации двух GetEnumerator методов, которые вам интересны (начиная с .NET 4.0). Они идентичны - они возвращают экземпляр вложенного типа Enumerator, с такими же аргументами для его конструктора. Единственное отличие - бокс типа struct во второй перегрузке:

// Used when you do foreach(var kvp in dict) { ... }

public Enumerator<TKey, TValue> GetEnumerator()
{
    return new Enumerator<TKey, TValue>
                ((SortedDictionary<TKey, TValue>) this, 1);
}

// Used when you do:
// foreach(var kvp in (ICollection<KeyValuePair<TKey, TValue>>)dict) { ... }
// or use LINQ to Objects on the collection.

IEnumerator<KeyValuePair<TKey, TValue>> 
IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
    return new Enumerator<TKey, TValue>
                ((SortedDictionary<TKey, TValue>) this, 1);
}

Фактически, единственная перегрузка GetEnumerator, которая имеет немного другую реализацию, - это метод IDictionary.GetEnumerator. Это изменяет аргумент в вызове конструктора, так что результирующий перечислитель создает DictionaryEntry экземпляров, а не KeyValuePair<,> экземпляров. Конечно, порядок перечисления будет таким же, как и для других перегрузок.

1 голос
/ 23 апреля 2011

Это зависит от реализации ключа IComparer по умолчанию, при условии, что вы не передаете его в:

SortedDictionary (Of TKey, TValue) требует реализации компаратора для сравнения ключей.Вы можете указать реализацию универсального интерфейса IComparer (Of T) с помощью конструктора, который принимает параметр сравнения;если вы не укажете реализацию, используется универсальный компаратор по умолчанию Comparer (Of T) .Default.Если тип TKey реализует универсальный интерфейс System.IComparable (Of T), эта реализация используется в компараторе по умолчанию.

Посмотрите на раздел Remarks страницы SortedDictionary<TKey, TValue>.

Таким образом, если ваш ключ - string, будет использована строковая реализация IComparable, если int32 - реализация int32.

...