Сохранение порядка с LINQ

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
379
0
57 371
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

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

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

поэтому, поскольку OrderBy является стабильной сортировкой, тогда: seq.OrderBy (_ => _.Key) разместит элементы в том же порядке, что и seq.GroupBy (_ => _.Key) .SelectMany (_ => _ ). Это верно?

dmg 02.02.2016 01:11

@dmg: Нет, не будет. Только GroupBy, за которым следует SelectMany, даст результаты, сгруппированные по ключам, но не в порядке возрастания ключей ... он выдаст их в том порядке, в котором ключи были изначально.

Jon Skeet 02.02.2016 01:54

вы говорите, что LINQ to SQL не сохраняет порядок?

symbiont 19.08.2016 11:39

@symbiont: Во многих операциях SQL является не имеет четко определенного порядка для начала. В основном я пытаюсь давать обещания только в том, что я могу гарантировать, например, в LINQ to Objects.

Jon Skeet 19.08.2016 11:48

@JonSkeet Если я использую OrderBy, гарантирует ли это, что n объектов с одним и тем же ключом сохранят свою исходную последовательность, за исключением того, что они все вместе. то есть: в list<x> {a b c d e f g}, если c, d, e все имеют один и тот же ключ, тогда результирующая последовательность будет содержать c, d, e рядом друг с другом AND в порядке c, d, e. Я не могу найти категорического ответа на основе MS.

Paulustrious 10.10.2017 21:28

@Paulustrious: в LINQ to Objects - да. У других поставщиков это зависит от реализации.

Jon Skeet 10.10.2017 21:29

@JonSkeet Ты в порядке. Вы ответили, пока я редактировал свой вопрос

Paulustrious 10.10.2017 21:35

@Paulustrious: From msdn.microsoft.com/en-us/library/bb534966(v=vs.110).aspx: «Этот метод выполняет стабильную сортировку; то есть, если ключи двух элементов равны, порядок элементов сохраняется. Напротив, нестабильная сортировка не сохраняет порядок элементов, которые имеют тот же ключ ".

Jon Skeet 10.10.2017 21:36

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

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

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

Но наиболее распространенные вещи (Выбрать, Куда, Пропустить, Взять) подойдут.

Если я не ошибаюсь, ToDictionary() просто не делает обещания о порядке, но на практике поддерживает порядок ввода (пока вы что-то из него не удалите). Я не говорю, что на это нужно полагаться, но «скремблирование» кажется неточным.

Timo 17.10.2017 16:42

Любые «группировать по» или «по порядку» могут изменить порядок.

Ответ принят как подходящий

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

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

  • AsEnumerable
  • Бросать
  • Concat
  • Выбирать
  • ToArray
  • Составлять список

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

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

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

  • ToDictionary
  • ToLookup

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

  • Сортировать по
  • OrderByDescending
  • Обратный
  • Тогда
  • ThenByDescending

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

  • GroupBy - объекты IGrouping выдаются в порядке, основанном на порядке элементов в источнике, которые создали первый ключ каждой IGrouping. Элементы в группе отображаются в том порядке, в котором они появляются в исходном тексте.
  • GroupJoin - GroupJoin сохраняет порядок элементов внешнего, а для каждого элемента внешнего - порядок совпадающих элементов из внутреннего.
  • Join - сохраняет порядок элементов внешнего и для каждого из этих элементов порядок совпадающих элементов внутреннего.
  • 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;
    }

На самом деле, я думаю, что Distinct сохраняет исходный (первый найденный) порядок - поэтому {1,2,1,3,1,3,4,1,5} будет {1,2,3,4,5}

Marc Gravell 15.10.2008 18:33
msdn.microsoft.com/en-us/library/bb348436.aspx The Distinct<(Of <(TSource>)>)(IEnumerable<(Of <(TSource>)>)) method returns an unordered sequence that contains no duplicate values.
Amy B 15.10.2008 18:47

Марк: то, что вы говорите, может быть правдой, но было бы плохой идеей полагаться на такое поведение.

Amy B 15.10.2008 18:52

@Amy B Я думаю, что было бы неразумно реализовывать Distinct (для linq для объектов) таким образом, чтобы не сохранять порядок, поскольку это будет работать хуже, чем если бы оно сохраняло порядок.

dan 14.07.2011 10:34

@dan пожимать плечами, если вы хотите нарушить документацию, решать вам.

Amy B 18.08.2011 05:16

@Amy B да, но это не относится к Linq to Objects. В Linq to Sql отдельный () помещает ключевое слово unique в сгенерированный sql, и упорядочение из sql не гарантируется. Мне было бы интересно увидеть реализацию отдельной для linq для объектов, которая не сохраняет порядок и более эффективна, чем та, которая сохраняет порядок. Например, вы можете использовать весь ввод и поместить его в хэш-набор, а затем получить значения, перечислив хэш-набор (порядок потери), но это еще хуже. Так что да, я не против время от времени бросать вызов документации :)

dan 19.08.2011 07:39

@Dan «Найден первым» разрушает порядок. В этом списке 1 стоит до и после 4. Если сделать его отдельным списком, упорядочение исчезнет.

Rangoric 31.08.2011 19:51

@Rangoric - зависит от вашего определения порядка сохранения. Если мы пойдем с FoundFirst for Distinct - можно предположить, что элементы фильтруются, а не переупорядочиваются. Единственная причина, по которой я не выбрал этот вариант, - это то, что в документации указано «неупорядоченный».

Amy B 02.09.2011 21:16

@ Эми, и вот почему. «Сначала найдено» - это не то же самое, что и «Отличное». Если наступит время, когда у кого-то есть способ сделать отличное, не сохраняя порядок, который быстрее, то, конечно, я не хочу сдерживать их из-за предположений.

Rangoric 03.09.2011 02:19

Возможно, документация (для метода Distinct) просто имела в виду «несортированный», а не «в непредсказуемом порядке». Я бы сказал, что Distinct относится к указанной выше категории фильтрации, как и Where.

Jeppe Stig Nielsen 20.09.2012 20:17

Я не уверен насчет select many, так как кроме двух foreach нет никаких других конструкций. О каком побочном эффекте вы говорите?

Johnny_D 10.03.2015 15:22

@Johnny_D Я подумал об использовании термина "побочный эффект" и решил отредактировать, поскольку он имеет значение в нашей области. Кроме того, когда я говорю о «сохранении порядка», я говорю с точки зрения изоморфизма порядка. Distinct и SelectMany не изоморфны по порядку.

Amy B 18.03.2015 15:22

Aren't Except, Intersect Union и т. д. Устанавливают операции? Я бы не поверил, что они вернутся в порядок. Это задокументировано?

nawfal 29.06.2015 22:37

@nawfal Intersect (msdn.microsoft.com/en-us/library/vstudio/…): «Наконец, отмеченные элементы выводятся в том порядке, в котором они были собраны». Except не документирует это, но его реализация, вероятно, будет очень похожей. Союз (msdn.microsoft.com/en-us/library/vstudio/…): цитата уже есть в ответе. Хотя эти операции можно описать как операции с наборами, они работают с IEnumerable <T>, и для их реализации имеет смысл иметь задокументированный порядок, основанный на порядке исходного IEnumerable.

Amy B 30.06.2015 02:33

@nawfal также обратите внимание: этот вопрос и ответ касаются LinqToObjects (методов System.Linq.Enumerable). Если вы используете Linq для чего-то еще (System.Linq.Queryable) - ничего из этого не применимо.

Amy B 30.06.2015 02:38

@AmyB Для ILookup: Объекты IGrouping <TKey, TElement> выдаются в порядке, основанном на порядке элементов в источнике, которые создали первый ключ каждого IGrouping <TKey, TElement>. Элементы в группе отображаются в том порядке, в котором они появляются в исходном тексте., взято из документации GroupBy. Поскольку ILookup имеет IGrouping, это гарантирует сохранение порядка, верно?

mbomb007 08.07.2015 19:51
github.com/dotnet/corefx/blob/master/src/System.Linq.Paralle‌ l /… ToLookup returns a Lookup. As you can see in the code, Lookup wraps a Dictionary. Because of this, Lookup has the same inconsistent ordering as Dictionary.
Amy B 17.11.2015 19:28
Уважать indeed wraps a dictionary but a special one: it maintains links between the elements to preserve the ordering of group keys, because it has to fulfil the documented ordering of GroupBy. Lookup is базовая структура данных обоихGroupBy and ToLookup. Therefore ToLookup preserves ordering just as well as Distinct does: neither is documented, both works (for ≥ 6 years now).
robert4 19.11.2015 14:24

Но поиск поддерживается простым словарем: _dict = new Dictionary <TKey, IGrouping <TKey, TElement >> (_ comparer); Значит ли это, что Словарь сохраняет порядок?

Amy B 19.11.2015 18:39

@Amy B Простой словарь сохраняет порядок (хотя и недокументированный) до тех пор, пока не удаляются элементы, но в Уважать используется нет. Его внутренний метод GetGrouping () содержит реализацию хеш-таблицы с вышеупомянутыми указателями .next, которые будут использоваться в GetEnumerator () (строка 3288).

robert4 23.11.2015 11:33

@ robert4 похоже, что ToLookup меняет порядок ключей, но элементы сохраняют порядок перечисляемого источника.

HuBeZa 02.02.2016 15:45

@HuBeZa можешь показать пример на dotnetfiddle.net? Мне это кажется невозможным. Вы говорите о Linq.Parallel или обычном (последовательном)?

robert4 02.02.2016 21:43

@ robert4 взгляните на ToLookup, который вызывает Lookup.Create. Он запускается последовательно для перечисляемого источника и вызывает Grouping.Add, инкапсулирующий простой буфер массива.

HuBeZa 03.02.2016 10:42

@HuBeZa Это доказывает, что порядок элементов сохраняется внутри групп, что я не подвергал сомнению. Я противоречил первой половине вашего утверждения: «ToLookup меняет порядок ключей». Lookup.Create вызывает lookup.GetGrouping () для каждого элемента источника, который создает группы таким образом, чтобы сохранить порядок ключей, как я подробно описал выше.

robert4 03.02.2016 16:00

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

Zach Mierzejewski 17.03.2017 19:05

@ZachMierzejewski Aggregate был исключен, поскольку он не возвращает IEnumerable. Без перечислимого результата порядок результатов не существует и не может быть определен как сохраненный или нет. Важно знать, что Aggregate обрабатывает ввод по порядку, как и все методы с источником IEnumerable.

Amy B 17.03.2017 19:57

Я думаю, это забавно, что никто никогда не просил меня перевести Union на Preserving Order ... у него такое же поведение Found First, как и у Distinct.

Amy B 08.06.2018 21:45

Так почему же, например, Skip (и другие вещи в списке сохраненного порядка) не возвращает IOrderedEnumerable?

ruffin 08.09.2018 00:27

@ruffin Было бы полезно подумать о том, для чего нужен IOrderedEnumerable<T>. Без этого интерфейса мы не смогли бы вызвать ThenBy. Есть ли смысл называть customers.Skip(5).ThenBy(c => c.Name)? Skip не определяет порядок - его реализация не меняет порядок.

Amy B 08.09.2018 10:47

Спасибо за ответ! Обратной стороной этого является заказ IEnumerableне гарантирует, и я бы не подумал, что могу рассчитывать на то, что что-то вернет IEnumerable «не меняет порядок». Было бы неприятно говорить, что функция, возвращающая неупорядоченный тип, гарантирует сохранение порядка неупорядоченного типа. Чего ждать? ; ^) Если customers имеет внутреннее представление о том, как он упорядочен (то есть формула, по которой он упорядочен, что, я признаю, я не думаю, что это так), то ваше использование Skip, по сути, имело бы смысл. orderedByCountyCustomers.Skip(5).ThenBy(c => c.Name)

ruffin 10.09.2018 18:14

Интересное продолжение вашего пункта в этом ответе Эрика Липперта и обсуждения со Скитом. По-прежнему кажется странным притворяться, что IEnumerable имеет порядок, который нужно сохранить, когда он не гарантирует порядок (то есть неявно неупорядочен) ... Я думаю, что, вероятно, мне лучше подумать, что IEnumerable может будет заказан, но не , сам по себе, гарантия ордер. IOrderedEnumerable, вероятно, тоже не лучшее название для того, что он делает ... IInTheProcessOfBeingOrderedEnumerable? / пожимает плечами Еще раз спасибо.

ruffin 10.09.2018 18:33

@ruffin большинство IEnumerable<T> имеют порядок (например, порядок индекса массива). Когда они это делают, порядок сохраняется операциями. Когда они этого не делают, нет порядка, который нужно сохранять. Все IOrderedEnumerable<T> имеют определенный порядок. Этот определенный порядок соблюдается и изменяется при обращении к ThenBy.

Amy B 10.09.2018 19:17

Я думаю, вы были правы, указав на документированное поведение Distinct, а не на его реализацию. Ничто не говорит о том, что .Net должен работать на архитектуре фон Неймана - в версии для машины подключения, возможно, не сохранение порядка было бы лучшей реализацией.

NetMage 29.11.2018 03:26

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

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

From Enumerable.GroupBy documentation:

The IGrouping<TKey, TElement> objects are yielded in an order based on the order of the elements in source that produced the first key of each IGrouping<TKey, TElement>. Elements in a grouping are yielded in the order they appear in source.

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

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

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

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

mysqlresult.OrderBy(e=>e.SomeColumn)

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

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