使用LINQ保留订单

时间:2008-10-15 12:20:13

标签: c# arrays linq sorting data-structures

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

6 个答案:

答案 0 :(得分:584)

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

完全保留订单。您可以按索引将源元素映射到结果元素

  • AsEnumerable
  • 角色
  • 的毗连
  • 选择
  • ToArray的
  • ToList

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

  • 鲜明
  • 相交
  • OfType
  • 跳过
  • SkipWhile
  • TakeWhile
  • 其中
  • Zip(.net 4中的新内容)

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

  • ToDictionary
  • ToLookup

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

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

根据某些规则重新定义订单。

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

编辑:我已根据此implementation移动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;
    }

答案 1 :(得分:31)

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

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

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

答案 2 :(得分:7)

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

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

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

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

答案 3 :(得分:3)

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

对于Enumerable方法(LINQ to Objects,适用于List<T>),您可以依赖SelectWhere或{{返回的元素的顺序1}}。对于GroupByToDictionary等天生无序的内容,情况并非如此。

  

来自Enumerable.GroupBy文档:

     

根据生成每个Distinct的第一个键的源中元素的顺序,按顺序生成IGrouping<TKey, TElement>个对象。分组中的元素按照它们在IGrouping<TKey, TElement>中的显示顺序产生。

source扩展方法(其他LINQ提供程序)不一定如此。

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

答案 4 :(得分:2)

任何'group by'或'order by'都可能会改变订单。

答案 5 :(得分:0)

这里的问题专门针对LINQ-to-Objects。

如果您使用的是LINQ-to-SQL,则那里没有命令,除非您强加以下命令:

mysqlresult.OrderBy(e=>e.SomeColumn)

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