Являются ли .Values и .Гарантируется ли сортировка ключей в ImmutableSortedDictionary?

#c#

#c#

Вопрос:

В C # являются .Values и .Ключи в ImmutableSortedDictionary гарантированно сортируются, пожалуйста?

Следующий код:

 var dict = new Dictionary<long, string>
        {
            {3, "Three"},
            {1, "One"},
            {2, "Two"}
        }.ToImmutableSortedDictionary();

        foreach (var p in dict)
        {
            System.Console.WriteLine($"{p.Key} - {p.Value}");
        }

        System.Console.WriteLine();

        foreach (var k in dict.Keys)
        {
            System.Console.WriteLine(k);
        }

        System.Console.WriteLine();

        foreach (var v in dict.Values)
        {
            System.Console.WriteLine(v);
        }
  

Ведет себя так, как я и ожидал, он печатает все по порядку. Есть ли какие-либо гарантии, что он всегда будет это делать? Я проверил онлайн-документацию, и она ничего не говорит так или иначе.

Спасибо.

РЕДАКТИРОВАТЬ: ни то, ни другое https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablesorteddictionary-2.keys?view=netcore-3.1 ни https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable.immutablesorteddictionary-2.values?view=netcore-3.1 скажем, так или иначе, из того, что я понимаю, документация гарантирует только то, что a .GetEnumerator() в словаре будет отсортирован. Итак, кажется, что первый цикл в приведенном выше коде всегда будет отсортирован, но я не уверен насчет второго и третьего.

Комментарии:

1. Да, в зависимости от типа ключа. Номера строк будут отсортированы «1»,»10″,»100″, «2»,»20″,»200″ в то время как числа будут сортировать 1,2,10,20,100,200.

2. Я думаю, что это не задокументировано должным образом. Свойства Keys and Values документируются только для реализации их соответствующих свойств IReadOnlyDictionary<TKey,TValue> интерфейса — который специально документирован как неуказанный порядок — «Порядок значений в перечислимой коллекции не указан» — но классы, реализующие оба свойства, должны гарантировать, что в свойствах and используется тот же порядок Keys Values .

3. Документы слабые, подразумевается, что вы будете работать с SortedDictionary .

4. @HansPassant Спасибо, документы для SortedDictionary learn.microsoft.com/en-us/dotnet/api /… укажите, что ключи упорядочены. Я склонен думать, что это упущение в документах ImmutableDictionary.

Ответ №1:

Ну, когда документ неясен, исходный код обсуждается (как указал @404).

Заключение

Я согласен с @mjwills. Поскольку в текущих документах (.NET Core 3.1) не указан порядок возвращаемых объектов, мы не можем с уверенностью предполагать что-либо.

Ключи:

Возвращает ключи в неизменяемом отсортированном словаре.

Значения:

Возвращает значения в неизменяемом отсортированном словаре.


Предупреждение

Поведение метода, приведенное ниже, основано на текущей реализации (.NET Core 3.1) ImmutableSortedDictionary . Это поведение может быть изменено, см. Заключение выше.

  • Keys вернет отсортированные результаты
  • Values не вернет отсортированные результаты

Это легко проверить, запустив код OP. Результат для Values не отсортирован.

 One
Two
Three
  

Причина

Оба Keys и Values являются результатом перечисления узла, который реализует IEnumerable<KeyValuePair<TKey, TValue>> .

 /// <summary>
/// Gets the keys.
/// </summary>
internal IEnumerable<TKey> Keys
{
    get { return Linq.Enumerable.Select(this, p => p.Key); }
}

/// <summary>
/// Gets the values.
/// </summary>
internal IEnumerable<TValue> Values
{
    get { return Linq.Enumerable.Select(this, p => p.Value); }
}
  

Node это реализация дерева AVL, которая добавляет / удаляет Node всегда на основе сравнения ключей (не значений) IComparer<TKey> keyComparer . Вот почему Keys всегда сортируются, а Values не сортируются сами по себе.

 /// <summary>
/// Adds the specified key. Callers are expected to have validated arguments.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <param name="keyComparer">The key comparer.</param>
/// <param name="valueComparer">The value comparer.</param>
/// <param name="overwriteExistingValue">if <c>true</c>, an existing key=value pair will be overwritten with the new one.</param>
/// <param name="replacedExistingValue">Receives a value indicating whether an existing value was replaced.</param>
/// <param name="mutated">Receives a value indicating whether this node tree has mutated because of this operation.</param>
/// <returns>The new AVL tree.</returns>
private Node SetOrAdd(TKey key, TValue value, IComparer<TKey> keyComparer, IEqualityComparer<TValue> valueComparer, bool overwriteExistingValue, out bool replacedExistingValue, out bool mutated)

/// <summary>
/// Removes the specified key. Callers are expected to validate arguments.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="keyComparer">The key comparer.</param>
/// <param name="mutated">Receives a value indicating whether this node tree has mutated because of this operation.</param>
/// <returns>The new AVL tree.</returns>
private Node RemoveRecursive(TKey key, IComparer<TKey> keyComparer, out bool mutated)
  

Комментарии:

1. Спасибо, в текущей реализации значения сортируются по ключу, чего я и ожидал.

Ответ №2:

По-видимому, он просто использует Select оператор linq для получения перечислителя для ключей и значений, найденных в источнике реализации. Таким образом, это гарантировало бы, что все 3 оператора будут отсортированы так, как можно было бы ожидать от его имени класса.

Комментарии:

1. So that would garantuee all 3 statements to be sorted as one also would expect from its class name. Это не гарантия. Это деталь реализации.

2. @mjwills но, основываясь на информации из документов в OP, которая гарантирует сортированный словарь для GetEnumerator базового класса, это не будет отличаться?

3. Ваша логика не соблюдается. Контракт не гарантирует , что он использует Select оператор. Таким образом, это не гарантирует , что они будут в порядке. Теперь имеет смысл , чтобы это работало таким образом — да. Но это не то же самое, что гарантия / контракт. Ничто не мешает реализации измениться в будущем.