使用LINQ保留订单

Mat*_*rut 346 c# linq arrays sorting data-structures

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

Amy*_*y B 615

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

绝对保留订单.您可以按索引将源元素映射到结果元素

  • AsEnumerable
  • CONCAT
  • 选择
  • ToArray的
  • ToList

保留订单.元素已过滤,但未重新排序.

  • 不同
  • 除了
  • 相交
  • OfType
  • 跳跃
  • SkipWhile
  • 采取
  • TakeWhile
  • 哪里
  • Zip(.net 4中的新内容)

销毁订单 - 我们不知道预期的订单会产生什么.

  • ToDictionary
  • 去查查看

明确重新定义订单 - 使用这些来更改结果的顺序

  • 排序依据
  • OrderByDescending
  • 相反
  • ThenBy
  • ThenByDescending

根据一些规则重新定义订单.

  • GroupBy - IGrouping对象的生成顺序基于源中元素的顺序,这些元素生成每个IGrouping的第一个键.分组中的元素按它们在源中出现的顺序生成.
  • GroupJoin - GroupJoin保留外部元素的顺序,对于外部的每个元素,内部匹配元素的顺序.
  • Join - 保留外部元素的顺序,并为每个元素保留内部匹配元素的顺序.
  • SelectMany - 对于源的每个元素,调用selector并返回一系列值.
  • Union - 枚举此方法返回的对象时,Union按该顺序枚举第一个和第二个,并生成尚未生成的每个元素.

编辑:我已根据此实现移动了Distinct to 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;
    }
Run Code Online (Sandbox Code Playgroud)

  • 马克:你说的可能是真的,但依靠这种行为是个坏主意. (12认同)
  • http://msdn.microsoft.com/en-us/library/bb348436.aspx Distinct <(Of <(TSource>)>)(IEnumerable <(Of <(TSource>)>))方法返回一个无序序列不包含重复值. (10认同)
  • @David B是但它不适用于Linq to Objects.在Linq to Sql中,distinct()将distinct关键字放入生成的sql中,并且不保证从sql进行排序.我有兴趣看到对于不保留顺序的对象的linq实现,并且比保留顺序的对象更有效.例如,您可以使用整个输入并将其放入哈希集中,然后通过枚举哈希集(丢失顺序)来产生值,但这更糟糕.所以,是的,我不介意时不时地反对文件:) (4认同)
  • 也许文档(对于`Distinct`方法)只是说"未分类",而不是"不可预测的顺序".我会说`Distinct`属于上面的过滤类别,就像`Where`. (4认同)
  • 实际上,我认为Distinct保留了原始(首次发现)订单 - 所以{1,2,1,3,1,3,4,1,5}将是{1,2,3,4,5} (2认同)
  • @ZachMierzejewski 聚合被排除,因为它不返回 IEnumerable。如果没有可枚举的结果,则结果的顺序不存在,并且无法定义是否保留。重要的是要知道 Aggregate 按顺序处理输入,与具有 IEnumerable 源的所有方法相同。 (2认同)

Jon*_*eet 31

你真的在谈论SQL,还是关于数组?换句话说,你使用LINQ to SQL或LINQ to Objects吗?

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

如果您转换为不同的数据结构,例如使用ToLookup或ToDictionary,我不相信订单会在那时保留 - 但这无论如何都有所不同.(我相信,映射到同一个键的值的顺序会保留用于查找.)


Mar*_*ell 7

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

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

请注意,将数据推送到Dictionary<,>(ToDictionary)会扰乱数据,因为字典不遵循任何特定的排序顺序.

但最常见的事情(Select,Where,Skip,Take)应该没问题.


Cur*_*lop 5

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

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

来自Enumerable.GroupBy文档:

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

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

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