Preserving order with LINQ

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.

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)

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

  • ToDictionary
  • ToLookup

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

  • OrderBy
  • OrderByDescending
  • Reverse
  • ThenBy
  • ThenByDescending

Redefines Order according to some rules.

  • 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.

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

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

Are you actually talking about SQL, or about arrays? To put it another way, are you using LINQ to SQL or 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.

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.)