用LINQ保持秩序

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

我检查了System.Linq.Enumerable的方法,放弃了返回非IEnumerable结果的东西。 我检查了每个的评论,以确定结果的顺序将如何与来源的顺序不同。

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

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

保留订单。 元素被过滤,但不被重新排序。

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

破坏秩序 – 我们不知道以什么顺序期望的结果。

  • ToDictionary
  • 去查查看

重新定义顺序显式 – 使用这些来改变结果的顺序

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

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

  • GroupBy – IGrouping对象按照产生每个IGrouping的第一个键的源元素的顺序产生。 分组中的元素按照它们在源代码中出现的顺序排序。
  • GroupJoin – GroupJoin保留外部元素的顺序,并且对于每个外部元素,从内部匹配元素的顺序。
  • 加入 – 保留外部元素的顺序,并且对于这些元素中的每一个,内部匹配元素的顺序。
  • SelectMany – 对于源的每个元素,调用选择器并返回一系列值。
  • Union – 枚举此方法返回的对象时,Union按此顺序枚举第一个和第二个,并产生尚未产生的每个元素。

编辑:我已经移动了基于这个实现保持秩序不同。

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

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

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

如果你转换为不同的数据结构,例如使用ToLookup或ToDictionary,我不相信顺序在这一点上保留 – 但是这有点不同。 (我相信,映射到同一个键的值的顺序被保留用于查找。)

如果你正在处理一个数组,这听起来像你正在使用LINQ到对象,而不是SQL; 你可否确认? 大多数LINQ操作不会重新排序(输出的顺序与输入顺序相同),所以不要使用其他排序(OrderBy [Descending] / ThenBy [Descending])。

正如Jon所说的更清楚一样。 LINQ通常会创建一个新的序列,只保留原始数据]

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

但最常见的东西(选择,在哪里,跳过,采取)应该没问题。

任何“按组”或“按顺序”都可能会改变顺序。

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

对于Enumerable方法(LINQ to Objects,适用于List<T> ),您可以依赖于SelectWhereGroupBy返回的元素的顺序。 对于像ToDictionaryDistinct这样天生无序的事物,情况并非如此。

从Enumerable.GroupBy文档:

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

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

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