C# 使用 LINQ 保留顺序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/204505/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:55:48  来源:igfitidea点击:

Preserving order with LINQ

c#arrayslinqsortingdata-structures

提问by Matthieu Durut

I use LINQ to Objects instructions on an ordered array. Which operations shouldn't I do to be sure the order of the array is not changed?

我在有序数组上使用 LINQ to Objects 指令。我不应该执行哪些操作来确保数组的顺序不会改变?

采纳答案by Amy B

I examined the methods of System.Linq.Enumerable, discarding any that returned non-IEnumerable results. I checked the remarks of each to determine how the order of the result would differ from order of the source.

我检查了System.Linq.Enumerable的方法,丢弃任何返回非 IEnumerable 结果的方法。我检查了每个人的评论,以确定结果的顺序与源的顺序有何不同。

Preserves Order Absolutely. You can map a source element by index to a result element

绝对保持秩序。您可以通过索引将源元素映射到结果元素

  • AsEnumerable
  • Cast
  • Concat
  • Select
  • ToArray
  • ToList
  • 可枚举
  • 投掷
  • 康卡特
  • 选择
  • 数组
  • 列表

Preserves Order. Elements are filtered or added, but not re-ordered.

保持秩序。元素被过滤或添加,但不会重新排序。

  • Distinct
  • Except
  • Intersect
  • OfType
  • Prepend (new in .net 4.7.1)
  • Skip
  • SkipWhile
  • Take
  • TakeWhile
  • Where
  • Zip (new in .net 4)
  • 清楚的
  • 除了
  • 相交
  • 类型
  • 前置(.net 4.7.1 中的新功能)
  • 跳过
  • 跳过时
  • 边走边看
  • 在哪里
  • Zip(.net 4 中的新功能)

Destroys Order - we don't know what order to expect results in.

破坏顺序 - 我们不知道期望结果是什么顺序。

  • ToDictionary
  • ToLookup
  • ToDictionary
  • 去查查看

Redefines Order Explicitly - use these to change the order of the result

Redefines Order Explicitly - 使用这些来改变结果的顺序

  • OrderBy
  • OrderByDescending
  • Reverse
  • ThenBy
  • ThenByDescending
  • 订购方式
  • 按降序排列
  • 逆转
  • 然后由
  • 然后按降序

Redefines Order according to some rules.

根据一些规则重新定义 Order。

  • GroupBy - The IGrouping objects are yielded in an order based on the order of the elements in source that produced the first key of each IGrouping. Elements in a grouping are yielded in the order they appear in source.
  • GroupJoin - GroupJoin preserves the order of the elements of outer, and for each element of outer, the order of the matching elements from inner.
  • Join - preserves the order of the elements of outer, and for each of these elements, the order of the matching elements of inner.
  • SelectMany - for each element of source, selector is invoked and a sequence of values is returned.
  • Union - When the object returned by this method is enumerated, Union enumerates first and second in that order and yields each element that has not already been yielded.
  • GroupBy - IGrouping 对象按基于源中生成每个 IGrouping 的第一个键的元素的顺序的顺序生成。分组中的元素按照它们在源中出现的顺序生成。
  • GroupJoin - GroupJoin 保留外部元素的顺序,并且对于外部的每个元素,匹配元素从内部开始的顺序。
  • 加入 - 保留外部元素的顺序,并且对于这些元素中的每一个,保留内部元素的匹配元素的顺序。
  • SelectMany - 对于源的每个元素,调用选择器并返回值序列。
  • Union - 当枚举此方法返回的对象时,Union 将依次枚举第一个和第二个并生成尚未生成的每个元素。


Edit: I've moved Distinct to Preserving order based on this implementation.

编辑:我已根据此实现将 Distinct 移至 Preserving order 。

    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;
    }

回答by Jon Skeet

Are you actually talking about SQL, or about arrays? To put it another way, are you using LINQ to SQL or LINQ to Objects?

您实际上是在谈论 SQL 还是在谈论数组?换句话说,您使用的是 LINQ to SQL 还是 LINQ to Objects?

The LINQ to Objects operators don't actually change their original data source - they build sequences which are effectively backed by the data source. The only operations which change the ordering are OrderBy/OrderByDescending/ThenBy/ThenByDescending - and even then, those are stable for equally ordered elements. Of course, many operations will filter out some elements, but the elements which are returned will be in the same order.

LINQ to Objects 操作符实际上并没有改变它们的原始数据源——它们构建了由数据源有效支持的序列。改变排序的唯一操作是 OrderBy/OrderByDescending/ThenBy/ThenByDescending - 即使这样,对于等序元素,这些操作也是稳定的。当然,很多操作都会过滤掉一些元素,但是返回的元素的顺序是一样的。

If you convert to a different data structure, e.g. with ToLookup or ToDictionary, I don't believe order is preserved at that point - but that's somewhat different anyway. (The order of values mapping to the same key is preserved for lookups though, I believe.)

如果您转换为不同的数据结构,例如使用 ToLookup 或 ToDictionary,我认为此时不会保留顺序 - 但无论如何这有点不同。(我相信,映射到相同键的值的顺序会保留用于查找。)

回答by Marc Gravell

If you are working on an array, it sounds like you are using LINQ-to-Objects, not SQL; can you confirm? Most LINQ operations don't re-order anything (the output will be in the same order as the input) - so don't apply another sort (OrderBy[Descending]/ThenBy[Descending]).

如果您正在处理数组,听起来您使用的是 LINQ-to-Objects,而不是 SQL;你可否确认?大多数 LINQ 操作不会对任何内容重新排序(输出将与输入的顺序相同)——因此不要应用其他排序(OrderBy[Descending]/ThenBy[Descending])。

[edit: as Jon put more clearly; LINQ generally creates a newsequence, leaving the original data alone]

[编辑:乔恩说得更清楚;LINQ一般会创建一个新的序列,只留下原始数据]

Note that pushing the data into a Dictionary<,>(ToDictionary) will scramble the data, as dictionary does not respect any particular sort order.

请注意,将数据推入Dictionary<,>(ToDictionary) 会打乱数据,因为字典不遵守任何特定的排序顺序。

But most common things (Select, Where, Skip, Take) should be fine.

但最常见的事情(选择、哪里、跳过、接受)应该没问题。

回答by leppie

Any 'group by' or 'order by' will possibly change the order.

任何“group by”或“order by”都可能会更改顺序。

回答by Curtis Yallop

I found a great answer in a similar question which references official documentation. To quote it:

我在参考官方文档的类似问题中找到了一个很好的答案。引用它:

For Enumerablemethods (LINQ to Objects, which applies to List<T>), you can rely on the order of elements returned by Select, Where, or GroupBy. This is not the case for things that are inherently unordered like ToDictionaryor Distinct.

对于Enumerable方法(LINQ到对象,它适用于List<T>),你可以依赖通过返回的元素的顺序SelectWhereGroupBy。对于像ToDictionary或等本质上无序的事物,情况并非如此Distinct

From Enumerable.GroupBydocumentation:

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.

来自Enumerable.GroupBy文档:

根据IGrouping<TKey, TElement>source 中生成 each 的第一个键的元素的顺序,按顺序生成对象IGrouping<TKey, TElement>。分组中的元素按照它们在 中出现的顺序产生source

This is not necessarily true for IQueryableextension methods (other LINQ providers).

对于IQueryable扩展方法(其他 LINQ 提供程序),这不一定是正确的。

Source: Do LINQ's Enumerable Methods Maintain Relative Order of Elements?

来源:LINQ 的可枚举方法是否保持元素的相对顺序?

回答by andrew pate

The question here is specifically referring to LINQ-to-Objects.

这里的问题特指LINQ-to-Objects。

If your using LINQ-to-SQL instead there is no order there unless you impose one with something like:

如果您使用 LINQ-to-SQL,则那里没有顺序,除非您强加以下内容:

mysqlresult.OrderBy(e=>e.SomeColumn)

If you do not do this with LINQ-to-SQL then the order of results can vary between subsequent queries, even of the same data, which could cause an intermittant bug.

如果您不使用 LINQ-to-SQL 执行此操作,则结果的顺序可能会在后续查询之间发生变化,即使是相同的数据,这可能会导致间歇性错误。