Saint
Saint

Reputation: 5469

Return to first element in foreach

Say I move with foreach loop in some collection.

At some point (e.g. by 4th elem) I want to return to first element of this collection (to go through all the elements again)

How to do this?

EDIT

Solution in comment by @dlev + enumerator.Reset()

Upvotes: 2

Views: 8417

Answers (9)

Tsabo
Tsabo

Reputation: 844

for(int i = 0;i<YourCollection.Count ; i++)
{
    if(YouNeedToStartOver)
    {
        i=-1;
        continue;
    }
}

Upvotes: 1

musefan
musefan

Reputation: 48415

Don't think there is anything build in but how about...

bool tryAgian = false;
do
{
   tryAgian = false;
   foreach(var item in items)
   {
      //do something
      if(needToStartAgain)
      {
         tryAgain = true;
         break;
      }
   }
} while(tryAgain)

EDIT: Optimised

Upvotes: 5

Eric Lippert
Eric Lippert

Reputation: 660088

Though this solution is inelegant, and plenty of people will tell you that it exposes you to all manner of danger, you can always just do:

Restart:
foreach(var item in things)
{
    DoSomething(item);
    if(WeShouldStartOver()) goto Restart;
}

That is easy, clear and correct. (A lot of people will reflexively tell you that gotos are the spawn of evil and always wrong. Those people might be confusing "inelegant" and "easily abused" with "morally wrong".)

If you're one of those people who thinks that gotos are always wrong, you can hide the goto. Mysteriously, when you spell "goto" as "while" and "break" it is no longer morally wrong!

bool loopTheLoop = true;
while(loopTheLoop)
{
    loopTheLoop = false;
    foreach(var item in things)
    {
        DoSomething(item);
        if(WeShouldStartOver())
        {
            loopTheLoop = true;
            break;
        }
    }
}

That is much longer, has way more complicated control flow, and uses a data flag just for control flow, rather than for expressing the meaning in the business domain of the program. I would argue that all of those things are as bad as the "goto", but some people really like this sort of thing.

I personally would be inclined to refactor the loop into a helper method:

while(LoopTheLoop()) {}
...
// Returns true if we bailed early, false if we did not.
bool LoopTheLoop()
{
    foreach(var item in things)
    {
        DoSomething(item);
        if(WeShouldStartOver()) return true;
    }
    return false;
}

Can you explain why you want to do this strange thing? Maybe there is a better way to do what you want. Because frankly, all these solutions are pretty bad.

Upvotes: 18

hoodaticus
hoodaticus

Reputation: 3880

You can't do this with a foreach loop over a collection, because when you use a foreach loop, you cannot get access to the Enumerator being used (it's hidden by the compiler - which is the whole point of the foreach loop!), and a collection does not necessarily have an indexer for direct access to the elements.

Even if you could, the interface contract for IEnumerator.Reset specifies that you do not have to implement Reset at all and can throw an exception instead. This means you cannot guarantee, for all collections, that Enumerator.Reset will return you to the beginning of the collection.

So no, you can't do what you have asked in the question; it is impossible.

Upvotes: -3

Jack7
Jack7

Reputation: 1341

you could do something of this sort

   private static void LoopMethod()
        {
           i= 0;
            foreach (string str in jack)
            {
                if (i == 4)
                    LoopMethod();

                Console.WriteLine(str);
                i++;
            }
        }

Upvotes: 0

tafa
tafa

Reputation: 7326

I would consider creating and using an Enumerator of the collection if I were you.

    using (IEnumerator<T> enumerator = collection.GetEnumerator())
    {

        while (enumerator.MoveNext())
        {
            if (SatisfyResetCondition(enumerator.Current))                          
                enumerator.Reset();
            Console.WriteLine(enumerator.Current);
        }
    }

Upvotes: -3

Joey
Joey

Reputation: 354536

Within a foreach you can only go to the next element with continue or step out of the loop completely. You would need to use the iterator directly.

Upvotes: 0

Shadow Wizard
Shadow Wizard

Reputation: 66389

You can't really do that as far as I know.

Just use different loop, for example while where you can control the iterator and decide if you increase or descrease it etc.

Upvotes: 1

devdigital
devdigital

Reputation: 34349

Use a for loop instead. Or a while loop.

Upvotes: 10

Related Questions