7

Question: Will the result of a LINQ query always be guaranteed to be in the correct order?

Example:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 

var lowNums = 
  from n in numbers 
  where n < 5 
  select n; 

Now, when we walk through the entries of the query result, will it be in the same order as the input data numbers is ordered?

foreach (var x in lowNums) 
  { 
    Console.WriteLine(x); 
  } 

If someone can provide a note on the ordering in the documentation, this would be perfect.

John Threepwood
  • 15,593
  • 27
  • 93
  • 149

2 Answers2

6
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Do you find any documentation that guarantees that the order keeps the same for Linq-To-Objects? – Tim Schmelter Aug 12 '13 at 22:18
  • @TimSchmelter I'm pretty sure the docs say the opposite, or rather, just say nothing at all. – evanmcdonnal Aug 12 '13 at 22:19
  • @evanmcdonnal: I'm fairly sure that the docs say nothing even if i'm sure that it doesn't change the order in `Select` or other linq methods. – Tim Schmelter Aug 12 '13 at 22:21
  • @TimSchmelter: The docs don't say anything about this, but when Microsoft changes this behavior, they will break an awful lot of clients, and Microsoft isn't fond of breaking clients. They will never change the `Enumerable.Where` to produce results that are in an other order. – Steven Aug 12 '13 at 22:21
  • 2
    Interesting though is that [the documents](http://msdn.microsoft.com/en-us/library/bb534501.aspx) do state that `group by` preserves its order. – Steven Aug 12 '13 at 22:23
  • 1
    @TimSchmelter yeah I had just corrected my comment to point out that it is just not mentioned. I agree that Microsoft will probably never change it. However, I would still write my code assuming order is not guaranteed. Especially since LINQ to Objects is the only one that works like that. I'd rather not base my software on a convenient coincidence. – evanmcdonnal Aug 12 '13 at 22:25
  • 1
    @evanmcdonnal: But if the input sequence was already ordered it would be redundant and inefficient to order it again. So it's important to know that the order doesn't change. Linq-To-Objects is incomparable with other providers that use a rdbms. – Tim Schmelter Aug 12 '13 at 22:28
  • @Steven True that. They won't even *fix* `OrderByDescending` – User 12345678 Aug 12 '13 at 22:31
  • @TimSchmelter I was actually thinking of 3rd party providers and ones that don't yet exist but assuming there is no performance loss (which I think would generally be the case) I would just do my LINQ queries before I do my sorting. – evanmcdonnal Aug 12 '13 at 22:35
0

I think the order of elements retrieved by a LINQ is preserved, at least for LINQ to Object, for LINQ to SQL or Entity, it may depend on the order of the records in the table. For LINQ to Object, I'll try explaining why it preserves the order.

In fact when the LINQ query is executed, the IEnumerable source will call to GetEnumerator() to start looping with a while loop and get the next element using MoveNext(). This is how a foreach works on the IEnumerable source. We all know that a foreach will preserve the order of the elements in a list/collection. Digging more deeply into the MoveNext(), I think it just has some Position to save the current Index and MoveNext() just increase the Position and yield the corresponding element (at the new position). That's why it should preserve the order, all the code changing the original order is redundant or by explicitly calling to OrderBy or OrderByDescending.

If you think this

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 
foreach(var i in numbers)
  if(i < 5) Console.Write(i + "  ");

prints out 4 1 3 2 0 you should think this

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; 
IEnumerator ie = numbers.GetEnumerator();
while(ie.MoveNext()){
  if((int)ie.Current < 5) Console.Write(ie.Current + "  ");
}

also prints out 4 1 3 2 0. Hence this LINQ query

var lowNums = from n in numbers 
              where n < 5 
              select n;
foreach (var i in lowNums) { 
   Console.Write(i + "  "); 
}

should also print out 4 1 3 2 0.

Conclusion: The order of elements in LINQ depends on how MoveNext() of an IEnumerator obtained from an IEnumerable is implemented. However, it's for sure that the order of elements in LINQ result will be the same order a foreach loop works on the elements.

King King
  • 61,710
  • 16
  • 105
  • 130