it-swarm.com.ru

Сохранение заказа с помощью LINQ

Я использую инструкции LINQ to Objects для упорядоченного массива. Какие операции не следует делать, чтобы убедиться, что порядок массива не изменился?

334
Matthieu Durut

Я проверил методы System.Linq.Enumerable , отбрасывая все, которые возвращали не-IEnumerable результаты. Я проверил замечания каждого из них, чтобы определить, как порядок результата будет отличаться от порядка источника.

Сохраняет порядок абсолютно. Вы можете сопоставить исходный элемент по индексу с результирующим элементом

  • AsEnumerable
  • В ролях
  • Concat
  • Выбрать
  • ToArray
  • К списку

Сохраняет заказ. Элементы фильтруются, но не переупорядочиваются.

  • Отчетливый
  • Кроме
  • Пересекаться
  • OfType
  • Пропускать
  • SkipWhile
  • Принимать
  • TakeWhile
  • Куда
  • Zip (новый в .net 4)

Уничтожает порядок - мы не знаем, в каком порядке следует ожидать результатов.

  • ToDictionary
  • ToLookup

Переопределить порядок явным образом - используйте их для изменения порядка результата

  • Сортировать по
  • OrderByDescending
  • Задний ход
  • ThenBy
  • ThenByDescending

Переопределяет заказ в соответствии с некоторыми правилами.

  • GroupBy - объекты IGrouping выдаются в порядке, основанном на порядке элементов в источнике, который создал первый ключ каждой IGrouping. Элементы в группировке приводятся в порядке их появления в источнике.
  • GroupJoin - GroupJoin сохраняет порядок элементов external, а для каждого элемента external - порядок соответствия элементов из inner.
  • Join - сохраняет порядок элементов external, а для каждого из этих элементов порядок совпадающих элементов inner.
  • SelectMany - для каждого элемента источника вызывается селектор и возвращается последовательность значений.
  • Union - когда перечисляется объект, возвращаемый этим методом, Union перечисляет первое и второе в этом порядке и возвращает каждый элемент, который еще не был получен.

Правка: я переместил Distinct в Сохранение порядка на основе этого реализация .

    private static IEnumerable<TSource> DistinctIterator<TSource>
      (IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
    {
        Set<TSource> set = new Set<TSource>(comparer);
        foreach (TSource element in source)
            if (set.Add(element)) yield return element;
    }
589
Amy B

Вы на самом деле говорите о SQL или о массивах? Другими словами, используете ли вы LINQ to SQL или LINQ to Objects?

Операторы LINQ to Objects на самом деле не изменяют свой исходный источник данных - они создают последовательности, которые эффективно поддерживаются источником данных. Единственными операциями, которые изменяют порядок, являются OrderBy/OrderByDescending/ThenBy/ThenByDescending - и даже в этом случае они стабильны для одинаково упорядоченных элементов. Конечно, многие операции отфильтровывают некоторые элементы, но возвращаемые элементы будут в том же порядке.

Если вы преобразуете в другую структуру данных, например, с ToLookup или ToDictionary я не верю, что порядок сохраняется в этот момент - но это все равно несколько иначе. (Порядок отображения значений для одного и того же ключа сохраняется для поиска, хотя, я считаю.)

31
Jon Skeet

Если вы работаете с массивом, похоже, что вы используете LINQ-to-Objects, а не SQL; Можешь подтвердить? Большинство операций LINQ ничего не упорядочивают (выходные данные будут в том же порядке, что и входные), поэтому не применяйте другую сортировку (OrderBy [Descending]/ThenBy [Descending]).

[править: как выразился Джон более четко; Обычно LINQ создает последовательность new, оставляя только исходные данные]

Обратите внимание, что помещение данных в Dictionary<,> (ToDictionary) приведет к шифрованию данных, поскольку словарь не учитывает какой-либо конкретный порядок сортировки.

Но наиболее распространенные вещи (выбрать, где, пропустить, взять) должны быть в порядке.

7
Marc Gravell

Я нашел отличный ответ в аналогичном вопросе, который ссылается на официальную документацию. Процитирую это:

Для методов Enumerable (LINQ to Objects, который применяется к List<T>) вы можете положиться на порядок элементов, возвращаемых Select, Where или GroupBy. Это не относится к вещам, которые изначально неупорядочены, например, ToDictionary или Distinct.

Из Enumerable.GroupBy документации:

Объекты IGrouping<TKey, TElement> выдаются в порядке, основанном на порядке элементов в источнике, который создал первый ключ каждого IGrouping<TKey, TElement>. Элементы в группировке выдаются в порядке их появления в source.

Это не обязательно верно для методов расширения IQueryable (других провайдеров LINQ).

Источник: Поддерживают ли перечисляемые методы LINQ относительный порядок элементов?

3
Curtis Yallop

Любое 'group by' или 'order by' может изменить порядок.

2
leppie

Вопрос здесь конкретно относится к LINQ-to-Objects.

Если вы используете LINQ-to-SQL вместо этого, там нет порядка, если вы не навязываете что-то вроде:

mysqlresult.OrderBy(e=>e.SomeColumn)

Если вы не сделаете это с LINQ-to-SQL, то порядок результатов может отличаться для последующих запросов, даже для одних и тех же данных, что может вызвать прерывистую ошибку.

0
andrew pate