Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to know I am getting the last element in the foreach loop

Tags:

c#

.net

I need to do special treatment for the last element in the collection. I am wondering if I can know I hit the last element when using foreach loop.

like image 804
user496949 Avatar asked Dec 20 '10 05:12

user496949


People also ask

How do you get the last record in foreach?

The last value is still available after the loop, so if you just want to use it for more stuff after the loop this is better: foreach($arr as $key=>$value) { //something } echo "last index! $key => $value"; If you do not want to treat the last value as special inside loops.

Does foreach run in order?

forEach calls callbackfn once for each element present in the array, in ascending order.

Does Break stop foreach?

break ends execution of the current for , foreach , while , do-while or switch structure.


2 Answers

Only way I know of is to increment a counter and compare with length on exit, or when breaking out of loop set a boolean flag, loopExitedEarly.

like image 76
Mitch Wheat Avatar answered Oct 30 '22 10:10

Mitch Wheat


There isn't a direct way. You'll have to keep buffering the next element.

IEnumerable<Foo> foos = ...

Foo prevFoo = default(Foo);
bool elementSeen = false;

foreach (Foo foo in foos)
{
    if (elementSeen) // If prevFoo is not the last item...
        ProcessNormalItem(prevFoo);

    elementSeen = true;
    prevFoo = foo;
}

if (elementSeen) // Required because foos might be empty.
    ProcessLastItem(prevFoo);

Alternatively, you could use the underlying enumerator to do the same thing:

using (var erator = foos.GetEnumerator())
{
    if (!erator.MoveNext())
        return;

    Foo current = erator.Current;

    while (erator.MoveNext())
    {
        ProcessNormalItem(current);
        current = erator.Current;
    }

    ProcessLastItem(current);
}

It's a lot easier when working with collections that reveal how many elements they have (typically the Count property from ICollection or ICollection<T>) - you can maintain a counter (alternatively, if the collection exposes an indexer, you could use a for-loop instead):

int numItemsSeen = 0;

foreach(Foo foo in foos)
{
   if(++numItemsSeen == foos.Count)
       ProcessLastItem(foo)

   else ProcessNormalItem(foo);
}

If you can use MoreLinq, it's easy:

foreach (var entry in foos.AsSmartEnumerable())
{
    if(entry.IsLast)
       ProcessLastItem(entry.Value)

    else ProcessNormalItem(entry.Value);
}

If efficiency isn't a concern, you could do:

Foo[] fooArray = foos.ToArray();

foreach(Foo foo in fooArray.Take(fooArray.Length - 1))
    ProcessNormalItem(foo);

ProcessLastItem(fooArray.Last());
like image 24
Ani Avatar answered Oct 30 '22 10:10

Ani