48

I have got a question about the order in IEnumerable.

As far as I am aware, iterating through IEnumerable is pseudo-code can be written in the following way:

while (enumerable.HasNext())
{
    object obj = enumerable.Current;
    ...
}

Now, assume, that one needs to operate on a sorted collection. Can IEnumerable be used in this case or is it better to try other means (i.e. IList) with indexation support?

In other words: does the contract of IEnumerable make any guarantees about the order in general?

So, IEnumerable is not a proper mean for a generic interface that guarantees ordering. The new question is what interface or class should be used for an immutable collection with order? ReadonlyCollection? IList? Both of them contain Add() method (even is not implemented in the former one).

My own thoughts: IEnumerable does not provide any guarantees about the ordering. The correct implementation could return same elements in different order in different enumerations (consider an SQL query)

I am aware of LINQ First(), but if IEnumerable does not say a word about it's ordering, this extension is pretty useless.

double-beep
  • 5,031
  • 17
  • 33
  • 41
undefined
  • 1,354
  • 1
  • 8
  • 19

4 Answers4

46

IEnumerable/IEnumerable<T> makes no guarantees about ordering, but the implementations that use IEnumerable/IEnumerable<T>may or may not guarantee ordering.

For instance, if you enumerate List<T>, order is guaranteed, but if you enumerate HashSet<T> no such guarantee is provided, yet both will be enumerated using the IEnumerable<T> interface.

spender
  • 117,338
  • 33
  • 229
  • 351
  • 1
    Another example is `Dictionary<,>`. It is clearly documented that the order in which its entries are enumerated is undefined. So code like `dict.Last().Key` (where `dict` is a `Dictionary<,>` and `Last()` is the LINQ extension method) makes no sense. (I heard of one developer doing exactly that.) – Jeppe Stig Nielsen May 02 '12 at 08:45
  • 1
    I'd add to already said that its important to understand correctly what is guarantees about the order for some generic collection. So the order guarantee is not about a particular order (say, as a result of sorting), but about guarantee that the order of elements of the same collection is the same for subsequent enumerations. Most of collections dont explicitly guarantee that. IList only represents a kind of dictionary where keys are indexes. – sich Aug 21 '12 at 09:30
  • IOrderedEnumerable may be a sign to believe that the collection guarantees the order (though the interface still doesn't), but its more than we need - it usually represents a particular SORT order, while we need ANY (random) order which is just guaranteed between enumerations. To conclude, only concrete implementation can really guarantee the order (e.g. Array, List). – sich Aug 21 '12 at 09:35
  • In the case described in the topic (the returned collection), it actually doesn't make any difference in what type of collection should be shown to the user (unless you want to claim your contract more explicitly), you only need the actual returned type to provide that ordering guarantee. – sich Aug 21 '12 at 10:55
  • Is it true that in the case of `List` order of enumeration is guaranteed? How do you know it? – Yola Sep 02 '20 at 14:01
  • @Yola Interesting. Is there a written contract of guarantee? I couldn't find it, but it's very much expected by many users. Were it to change to a non-linear order of enumeration, it would break plenty of existing code. https://stackoverflow.com/a/11680665/14357 – spender Sep 02 '20 at 16:53
14

Implementation detail. IEnumerable will enumerate the item - how that is implemented is up to the implementation. MOST lists etc. run along their natural order (index 0 upward etc.).

does the contract of IEnumerable guarantee us some order in general case?

No, it guarantees enumeration only (every item one time etc.). IEnumerable has no guaranteed order because it is also usable on unordered items.

I know about LINQ First(), but if IEnumerable does not say a word about it's order, this extension is rather useless.

No, it is not, because you may have intrinsic order. You give SQL as example - the result is an IEnumerable, but if I have enforced ordering before (By using OrderBy()) then the IEnumerable is ordered per definition of LINQ. AsEnumerable().First() gets me then the first item by Order.

Aurélien Gasser
  • 3,043
  • 1
  • 20
  • 25
TomTom
  • 61,059
  • 10
  • 88
  • 148
7

Perhaps you are looking for the IOrderedEnumerable interface? It is returned by extensions methods like OrderBy() and allow for subsequent sorting with ThenBy().

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • 4
    Unfortunately this won't work if you want to accept interfaces like IList which do guarantee an order but do not do not inherit from IOrderedEnumerable. See http://stackoverflow.com/q/5429974/1157054 – Ajedi32 Feb 02 '17 at 17:11
4

You mix two points: enumerating and ordering.

When you enumerate over IEnumerable you should not care about order. You work with the interface, and its implementation should care about order.

For instance:

void Enumerate(IEnumerable sequence)
{
    // loop
}

SortedList<T> sortedList = ...
Enumerate (sortedList);

Inside the method it's still a list with fixed order, but method doesn't know about particular interface implementation and it's peculiarity.

Aurélien Gasser
  • 3,043
  • 1
  • 20
  • 25
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • Don't mix sorting and ordering. `SortedList` stores items in order by keys, but OP might require some other arbitrary order – Yarek T Jan 04 '22 at 15:53