#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
andValues
документируются только для реализации их соответствующих свойств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
оператор. Таким образом, это не гарантирует , что они будут в порядке. Теперь имеет смысл , чтобы это работало таким образом — да. Но это не то же самое, что гарантия / контракт. Ничто не мешает реализации измениться в будущем.