Let's say I have a sequence.
IEnumerable<int> sequence = GetSequenceFromExpensiveSource();
// sequence now contains: 0,1,2,3,...,999999,1000000
Getting the sequence is not cheap and is dynamically generated, and I want to iterate through it once only.
I want to get 0 - 999999 (i.e. everything but the last element)
I recognize that I could do something like:
sequence.Take(sequence.Count() - 1);
but that results in two enumerations over the big sequence.
Is there a LINQ construct that lets me do:
sequence.TakeAllButTheLastElement();
I don't know a Linq solution - But you can easily code the algorithm by yourself using generators (yield return).
Or as a generalized solution discarding the last n items (using a queue like suggested in the comments):
The solution that I use for this problem is slightly more elaborate.
My util static class contains an extension method
MarkEnd
which converts theT
-items inEndMarkedItem<T>
-items. Each element is marked with an extraint
, which is either 0; or (in case one is particularly interested in the last 3 items) -3, -2, or -1 for the last 3 items.This could be useful on its own, e.g. when you want to create a list in a simple
foreach
-loop with commas after each element except the last 2, with the second-to-last item followed by a conjunction word (such as “and” or “or”), and the last element followed by a point.For generating the entire list without the last n items, the extension method
ButLast
simply iterates over theEndMarkedItem<T>
s whileEndMark == 0
.If you don’t specify
tailLength
, only the last item is marked (inMarkEnd()
) or dropped (inButLast()
).Like the other solutions, this works by buffering.
A simple way would be to just convert to a queue and dequeue until only the number of items you want to skip is left.
Could be:
I guess it should be like de "Where" but preserving the order(?).
Nothing in the BCL (or MoreLinq I believe), but you could create your own extension method.
if you don't have time to roll out your own extension, here's a quicker way: