I have an IEnumerable
Similar to Marc's answer, but you could write an extension method to wrap it up.
public static class LastEnumerator
{
public static IEnumerable<MetaEnumerableItem<T>> GetLastEnumerable<T>(this IEnumerable<T> blah)
{
bool isFirst = true;
using (var enumerator = blah.GetEnumerator())
{
if (enumerator.MoveNext())
{
bool isLast;
do
{
var current = enumerator.Current;
isLast = !enumerator.MoveNext();
yield return new MetaEnumerableItem<T>
{
Value = current,
IsLast = isLast,
IsFirst = isFirst
};
isFirst = false;
} while (!isLast);
}
}
}
}
public class MetaEnumerableItem<T>
{
public T Value { get; set; }
public bool IsLast { get; set; }
public bool IsFirst { get; set; }
}
Then call it like so:
foreach (var row in records.GetLastEnumerable())
{
output(row.Value);
if(row.IsLast)
{
outputLastStuff(row.Value);
}
}
not 100% sure I like this but you could always delay the use of item until you've moved one step in to the IEnumerable array, that way when you get to the end you've not used the last entry.
it avoids having to force a count on the enumerator.
object item = null;
foreach (var a in items)
{
// if item is set then we can use it.
if (item != null)
{
// not final item
f(item);
}
item = a;
}
// final item.
g(item);
Since you mention IEnumerable[<T>]
(not IList[<T>]
etc), we can't rely on counts etc: so I would be tempted to unroll the foreach
:
using(var iter = source.GetEnumerator()) {
if(iter.MoveNext()) {
T last = iter.Current;
while(iter.MoveNext()) {
// here, "last" is a non-final value; do something with "last"
last = iter.Current;
}
// here, "last" is the FINAL one; do something else with "last"
}
}
Note the above is technically only valid for IEnuemerable<T>
; for non-generic, you'd need:
var iter = source.GetEnumerator();
using(iter as IDisposable) {
if(iter.MoveNext()) {
SomeType last = (SomeType) iter.Current;
while(iter.MoveNext()) {
// here, "last" is a non-final value; do something with "last"
last = (SomeType) iter.Current;
}
// here, "last" is the FINAL one; do something else with "last"
}
}
If you want to do this as efficiently as possible there is no other choice than effectively looking at not only the current but also the "next" or "previous" item, so you can defer the decision of what to do after you have that information. For example, assuming T
is the type of items in the collection:
if (collection.Any()) {
var seenFirst = false;
T prev = default(T);
foreach (var current in collection) {
if (seenFirst) Foo(prev);
seenFirst = true;
prev = current;
}
Bar(prev);
}
See it in action.
I wouldn't really recommend it, but I guess you could do something like this...
object m_item = notPartOfListFlag = new object();
foreach(var item in enumerator){
if(m_item != notPartOfListFlag)
{
//do stuff to m_item;
}
m_item = item;
}
//do stuff to last item aka m_item;
But I would try to use some kind of collection that exposes the position of the items in the list, then use
if(collection.IndexOf(item) == collection.Count-1) do stuff