Terco
Terco

Reputation: 920

How to Know This is the Last Iteration of a Loop?

Is there a fancy way to know you are in the last loop in a List without using counters

List<string> myList = new List<string>() {"are", "we", "there", "yet"};

foreach(string myString in myList) {
    // Is there a fancy way to find out here if this is the last time through?
}

Upvotes: 8

Views: 8509

Answers (9)

Justin Morgan
Justin Morgan

Reputation: 30700

Depends on your definition of "fancy". This might qualify:

if (myList.Count > 0)
{
    myList.Take(myList.Count - 1)).ForEach(myString => doSomething(myString));
    doSomethingElse(myList.Last());
}

To me, that seems close to what you're looking for. Note that it's not super high-peformance, but it's short and pretty readable, at least to my eyes. You could also write it this way:

if (myList.Count > 0)
{
    foreach (string myString in myList.Take(myList.Count - 1))
    {
         doSomething(myString);
    }

    doSomethingElse(myList.Last());
}

Here's another alternative, which I'd consider the most obvious, but it's probably the fastest way of doing this:

if (myList.Count > 0)
{
    for (int i = 0; i < myList.Count - 1; i++)
    {
        doSomething(myList[i]);
    }

    doSomethingElse(myList.Count - 1);
}

Upvotes: 0

Nicholas Carey
Nicholas Carey

Reputation: 74317

The "fancy" way is to maintain 1 element of lookahead, but why on earth would you want to? Jus maintain a count. Here's the fancy way. No counters, no checking the Count property. All it uses is an enumerator:

using System;
using System.Collections.Generic;

namespace Sandbox
{
  class Program
  {

    enum ListPosition : byte
    {
      First     = 0x01       ,
      Only      = First|Last ,
      Middle    = 0x02       ,
      Last      = 0x04       ,
      Exhausted = 0x00       ,
    }

    private static void WalkList( List<int> numbers )
    {
      List<int>.Enumerator numberWalker = numbers.GetEnumerator();
      bool                 currFetched  = numberWalker.MoveNext();
      int                  currValue    = currFetched ? numberWalker.Current : default( int );
      bool                 nextFetched  = numberWalker.MoveNext();
      int                  nextValue    = nextFetched ? numberWalker.Current : default( int );
      ListPosition         position     ;

      if      (   currFetched &&   nextFetched ) position = ListPosition.First     ;
      else if (   currFetched && ! nextFetched ) position = ListPosition.Only      ;
      else if ( ! currFetched                  ) position = ListPosition.Exhausted ;
      else throw new InvalidOperationException( "Reached Unreachable Code. Hmmm...that doesn't seem quite right" );

      while ( position != ListPosition.Exhausted )
      {
        string article = ( position==ListPosition.Middle?"a":"the" );

        Console.WriteLine( "  {0} is {1} {2} item in the list" , currValue , article , position );

        currFetched = nextFetched ;
        currValue   = nextValue   ;

        nextFetched = numberWalker.MoveNext()                         ;
        nextValue   = nextFetched?numberWalker.Current:default( int ) ;

        if      (   currFetched &&   nextFetched ) position = ListPosition.Middle    ;
        else if (   currFetched && ! nextFetched ) position = ListPosition.Last      ;
        else if ( ! currFetched                  ) position = ListPosition.Exhausted ;
        else throw new InvalidOperationException( "Reached Unreachable Code. Hmmm...that doesn't seem quite right" );

      }

      Console.WriteLine() ;
      return ;
    }

    static void Main( string[] args )
    {
      List<int> list1 = new List<int>( new []{ 1 ,             } ) ;
      List<int> list2 = new List<int>( new []{ 1 , 2 ,         } ) ;
      List<int> list3 = new List<int>( new []{ 1 , 2 , 3 ,     } ) ;
      List<int> list4 = new List<int>( new []{ 1 , 2 , 3 , 4 , } ) ;

      Console.WriteLine( "List 1:" ) ; WalkList( list1 ) ;
      Console.WriteLine( "List 2:" ) ; WalkList( list2 ) ;
      Console.WriteLine( "List 3:" ) ; WalkList( list3 ) ;
      Console.WriteLine( "List 4:" ) ; WalkList( list4 ) ;

      return ;
    }

  }
}

Upvotes: 0

David Yaw
David Yaw

Reputation: 27864

There are two ways I would do it.

First, with a for loop instead of foreach

for(int i = 0; i < myList.Count; i++)
{
    string myString = myList[i];
    bool isLast = i == myList.Count - 1;

    ...
}

Or, if this needs to work with enumerators, change the order of things. Normally MoveNext is done as the control of the while loop, but if we do it right at the beginning of the loop, we can use its return to determine if we're at the end of the list or not.

IEnumerator<string> enumerator = myList.GetEnumerator();
bool isLast = !enumerator.MoveNext();
while(!isLast)
{
    string myString = enumerator.Current;
    isLast = !enumerator.MoveNext();

    ...
}

Upvotes: 4

marcoaoteixeira
marcoaoteixeira

Reputation: 505

Well...there is no way to know that. Not as easy as you might guess. The list data structure is just a way to order items one after another. But you don't have a way to say if a item is the last item just using foreach structure. Best use for structure with the count property to know if you hit the last (or previous) item.

var length = list.Count;

for (var idx = 0; idx < list.Count; idx++)
{
    if (idx == (length - 1))
    {
        // The last item. Do something
    }
}

hope it helps.

Upvotes: 1

Rob Levine
Rob Levine

Reputation: 41328

How about using a for loop instead?

List<string> myList = new List<string>() {"are", "we", "there", "yet"};

for (var i=0; i<myList.Count; i++)
{
   var myString = myList[i];
   if (i==myList.Count-1)
   {
      // this is the last item in the list
   }
}

foreach is useful - but if you need to keep count of what you are doing, or index things by count, then just revert to a good old for loop.

Upvotes: 4

Elian Ebbing
Elian Ebbing

Reputation: 19057

No, you will have to use a regular for(int i=0; i<myList.Length; i++) { ... } loop for that.

Upvotes: 10

archil
archil

Reputation: 39501

Use for operator instead of foreach

Upvotes: 0

Jonathan Wood
Jonathan Wood

Reputation: 67283

There's no efficient way to do this.

Just use a for loop and index. It runs faster any way.

Upvotes: 1

Femaref
Femaref

Reputation: 61467

No, there isn't, you'll have to use a counter if you want to use foreach.

Upvotes: 0

Related Questions