SortedList и Linq

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

https://msdn.microsoft.com/en-us/library/ms132319(v=vs.110).aspx

Я предполагаю, что перечисление гарантированно будет отсортировано, а также получено по индексу, но как насчет значений и ключей? Все ли эти случаи безопасны?

        var list = new SortedList<DateTime, object>();

        //add entries here ...

        var firstValue1 = list.Values[0];
        var firstValue2 = list.First().Value;
        var firstValue3 = list.Values.First();

        var firstKey1 = list.Keys[list.Count-1];
        var firstKey2 = list.First().Key;
        var firstKey3 = list.Keys.First();

        var sortedList = list.Where(x => x.Key > DateTime.Now)
            .Select(x => x.Value);

3 ответа

Решение

Прочитайте документацию...

Из документации по свойству Значения:

"Порядок значений в IList<T> такой же, как порядок в SortedList<TKey, TValue>".

Из документации на свойство Keys:

"Порядок ключей в IList<T> такой же, как порядок в SortedList<TKey, TValue>".

Если вы посмотрите на исходный код Enumerable.cs, вы увидите, что перегрузка без предиката просто пытается обработать источник как IList, и если это не работает, он возвращает первый элемент, используя перечислитель. И индекс, и перечислитель должны обрабатываться внутренне классом SortedList, так что вы получите соответствующий (отсортированный) результат:

public static TSource First<TSource>(this IEnumerable<TSource> source) {
            if (source == null) throw Error.ArgumentNull("source");
            IList<TSource> list = source as IList<TSource>;
            if (list != null) {
                if (list.Count > 0) return list[0];
            }
            else {
                using (IEnumerator<TSource> e = source.GetEnumerator()) {
                    if (e.MoveNext()) return e.Current;
                }
            }
            throw Error.NoElements();
        }

Перегрузка с помощью предиката работает немного иначе, так как он выполняет предикат для каждого элемента с помощью перечислителя, ища первое совпадение:

    public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
        if (source == null) throw Error.ArgumentNull("source");
        if (predicate == null) throw Error.ArgumentNull("predicate");
        foreach (TSource element in source) {
            if (predicate(element)) return element;
        }
        throw Error.NoMatch();
    }

В любом случае, вы должны получить тот же (отсортированный) результат.

Вы можете проверить исходный код здесь:

https://referencesource.microsoft.com/#System/compmod/system/collections/generic/sortedlist.cs,de670561692e4a20

По-видимому, Keys Свойство - это просто оболочка вокруг экземпляра этого класса:

https://referencesource.microsoft.com/#System/compmod/system/collections/generic/sortedlist.cs,374aa21b960ae2e2

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

https://referencesource.microsoft.com/#System/compmod/system/collections/generic/sortedlist.cs,a4492235f85c77d8

Насколько я могу судить, MoveNext() это просто перебирает ключи от SortedList,

Вы можете узнать так же, как Values работает.

Другие вопросы по тегам