0

This feels like an obvious requirement, but LINQ is fighting me.

I have collection of objects that I need to order. So my interface returns an IOrderedEnumerable.

Requirements change, and now I only need to take the first 10 elements. So I use .Take(), but now it returns IEnumerable (technically it is returning an OrderedPartition, but that doesn't implement IOrderedEnumerable so I can't even cast). To conform to my existing interface, I now need to do the nasty (order, then take, then order again):

Dictionary<string, int> tagCounts = ...
IOrderedEnumerable<KeyValuePair<string, int>> orderedTags = tagCounts
    .OrderByDescending(kvp => kvp.Value)
    .Take(10)
    .OrderByDescending(kvp => kvp.Value);

Surely this is a problem that has been solved. Is there a nice way to take the top x ordered items, and keep them ordered?

Ian
  • 1,475
  • 2
  • 15
  • 31

1 Answers1

0

Just return IEnumerable then from your method. Changing the returned interface does not change the behavior of the returned enumerable during the enumeration.

Take and Skip methods should preserve order. From remarks in the docs:

Returns a specified number of contiguous elements from the start of a sequence.

The Take and Skip methods are functional complements. Given a collection sequence coll and an integer n, concatenating the results of coll.Take(n) and coll.Skip(n) yields the same sequence as coll.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • `IEnumerable` does not guarantee order. Whilst it is likely the underlying implementation will maintain the order after `Take`, it seems like poor design for a public interface. – Ian Feb 08 '23 at 23:41
  • @Ian the same way you can say that `IEnumerable`/`IOrderedEnumerable` does nor guarantee that it will not add new elements, so the `Take` is not satisfied also. Also see [this](https://stackoverflow.com/questions/204505/preserving-order-with-linq) – Guru Stron Feb 08 '23 at 23:59
  • @Ian also non-preserving order implementation of `Take` does not make much sense and should fail to satisfy the quoted (see the update) guarantee. – Guru Stron Feb 09 '23 at 00:06
  • Yes, I saw that post saying that `Take` will preserve order. I couldn't find a more authoritative source. And yes, I agree that if it does not preserve order, it will break the take/skip rules. So the MSDN documentation _implies_ that it will preserve order. But it feels like a massive step backwards to revert `IOrderedEnumerable` to a simple `IEnumerable`. I'd rather do the nasty and call `OrderBy` again to maintain the return type. I just thought there must be a nicer solution. It would be niceif there was a `Take` extension that operates on *and* returns `IOrderedEnumerable` – Ian Feb 09 '23 at 04:13