Continue in while inside foreach - c#

In the following C# code snippet
I have a 'while' loop inside a 'foreach' loop and I wish to jump to the next item in 'foreach' when a certain condition occurs.
foreach (string objectName in this.ObjectNames)
{
// Line to jump to when this.MoveToNextObject is true.
this.ExecuteSomeCode();
while (this.boolValue)
{
// 'continue' would jump to here.
this.ExecuteSomeMoreCode();
if (this.MoveToNextObject())
{
// What should go here to jump to next object.
}
this.ExecuteEvenMoreCode();
this.boolValue = this.ResumeWhileLoop();
}
this.ExecuteSomeOtherCode();
}
'continue' would jump to the beginning of the 'while' loop not the 'foreach' loop.
Is there's a keyword to use here, or should I just use goto which I don't really like.

Use the break keyword. That will exit the while loop and continue execution outside it. Since you don't have anything after the while, it would loop around to the next item in the foreach loop.
Actually, looking at your example more closely, you actually want to be able to advance the for loop without exiting the while. You can't do this with a foreach loop, but you can break down a foreach loop to what it actually automates. In .NET, a foreach loop is actually rendered as a .GetEnumerator() call on the IEnumerable object (which your this.ObjectNames object is).
The foreach loop is basically this:
IEnumerator enumerator = this.ObjectNames.GetEnumerator();
while (enumerator.MoveNext())
{
string objectName = (string)enumerator.Value;
// your code inside the foreach loop would be here
}
Once you have this structure, you can call enumerator.MoveNext() within your while loop to advance to the next element. So your code would become:
IEnumerator enumerator = this.ObjectNames.GetEnumerator();
while (enumerator.MoveNext())
{
while (this.ResumeWhileLoop())
{
if (this.MoveToNextObject())
{
// advance the loop
if (!enumerator.MoveNext())
// if false, there are no more items, so exit
return;
}
// do your stuff
}
}

The following should do the trick
foreach (string objectName in this.ObjectNames)
{
// Line to jump to when this.MoveToNextObject is true.
this.ExecuteSomeCode();
while (this.boolValue)
{
if (this.MoveToNextObject())
{
// What should go here to jump to next object.
break;
}
}
if (! this.boolValue) continue; // continue foreach
this.ExecuteSomeOtherCode();
}

The break; keyword will exit a loop:
foreach (string objectName in this.ObjectNames)
{
// Line to jump to when this.MoveToNextObject is true.
while (this.boolValue)
{
// 'continue' would jump to here.
if (this.MoveToNextObject())
{
break;
}
this.boolValue = this.ResumeWhileLoop();
}
}

Use goto.
(I guess people will be mad with this response, but I definitely think it's more readable than all other options.)

You can use "break;" to exit the innermost while or foreach.

Related

Foreach with continue -- unexpected behavior

I'm trying to iterate over a atring to count the number of occurrences of a certain types of characters.
However, I'm not sure what the problem with my logic is.
foreach (var character in stringToCount)
{
if (char.IsLetterOrDigit(character))
{
alphaNumericCount++;
continue;
}
if (char.IsLower(character))
{
lowercaseCount++;
continue;
}
if (char.IsUpper(character))
{
uppercaseCount++;
continue;
}
}
Only the alphaNumericCount variable is being incremented, and any lowercase or uppercase character is being ignored. I think I've misunderstood the use of the continue keyword.
If I comment out the first if statement then somehow the lowercase and uppercase checks work.
What am I doing wrong?
Edit: Thank you everyone for your replies, they are all very good and informative. If I could award multiple correct answers I would!
The continue keyword jumps to the next letter in the string (the next foreach iteration). If you pass a lower case letter, it will increment in the first if statement, then move on to the next letter.
In your case, just remove the continue statements completely, and it will likely work as you expect.
continue breaks out of the foreach loop for the given item. Since any letter is alphanumeric, it hits the first continue and "jumps" out, never giving the other statements a chance to run.
In your case, it sounds like you should remove all instances of that keyword. In general, "jumping" out of loops like that should be done with caution, as it can cause bugs like this.
Note: break can be used in for and while loops to do the same thing, and comes with the same caution.
You should use else if:
foreach (var character in stringToCount)
{
if (char.IsLetterOrDigit(character))
{
alphaNumericCount++;
if (char.IsLower(character))
lowercaseCount++;
else if (char.IsUpper(character))
uppercaseCount++;
}
}
Because Continue skips the remaining code of the current iteration and jumps to the next iteration.
continue (C# Reference)
The continue statement passes control to the next
iteration of the enclosing while, do, for, or foreach statement in
which it appears.
From within a loop, you have two keywords that affect the flow of control:
break - Is like a goto END
continue - Is like a goto NEXT
In C#, the foreach() loop on an IEnumerable (or any object that provides a GetEnumerator() method with a proper enumerator object is implemented by first getting the enumerator object for the collection, visiting each item in the collection (enumerator) with enumerator.MoveNext(), and accessing that current item with enumerator.Current;
As a mental exercise, if you did not have foreach() or any other looping construct, you could implement it with goto and labels.
foreach(var item in container) // translates to lines 1 - 4 below
{
if(foo) continue; // line 5
if(bar) break; // line 6
// do something
}
translates to
1: var enumerator = container.GetEnumerator(); // initialize the enumerator
2: next: if(enumerator.MoveNext())
3: {
4: var item = enumerator.Current; // get item to work on (the "topic")
5: if(foo) goto next; // 'continue' keyword - skips to next
6: if(bar) goto end; // 'break' keyword - exits loop
7: // do something
8: goto next; // normal loop iteration to next item
9: }
10: end: // loop done
As per the question, if you want to hit multiple conditions in the same loop, don't use continue at all; continue will skip everything after it for the current iteration. Use separate independent conditions so they all have the chance to execute.
This is by far the most readable method in my opinion:
int alphaNumericCount = stringToCount.Count(char.IsLetterOrDigit);
int lowercaseCount = stringToCount.Count(char.IsLower);
int uppercaseCount = stringtoCount.Count(char.IsUpper);
If you can't stand to repeat the iterations then:
foreach(var c in stringToCount.Where(char.IsLetterOrDigit))
{
++alphaNumericCount;
if (char.IsLower(c)) ++lowercaseCount;
if (char.IsUpper(c)) ++uppercaseCount;
}

How to repeat one loop in foreach

Hi guys how can you repeat one iteration in a foreach?
foreach (string line in File.ReadLines("file.txt"))
{
// now line == "account", next line == "account1"
if (line.Contains("a"))
//next loop take "account1";
else
// need to set that next loop will take line == "account" again
}
How to do it?
While I don't fully understand your example, I think I understand your question. I had the same problem and was able to come up with a solution: include a while loop within the foreach. In your example it would look like this:
foreach (string line in File.ReadLines("file.txt"))
{
bool repeat = true;
while (repeat)
{
// now line == "account", next line == "account1"
if (line.Contains("a"))
{
//do your logic for a break-out case
repeat = false;
}
else
{
//do your logic for a repeat case on the same foreach element
//in this instance you'll need to add an "a" to the line at some point, to avoid an infinite loop.
}
}
}
I know I'm very late to the game, but hopefully this will be helpful for anyone else who stumbles in here with the same problem.
There is no need to change your code, assuming it only has an if/else construct in the loop.
When the if condition evaluates to true the else will not execute and the loop resumes.
In a more complex where you want to immediately resume the loop and ensure nothing else following the condition executes, use the continue statement:
The continue statement passes control to the next iteration of the enclosing while, do, for, or foreach statement in which it appears.
foreach (string line in File.ReadLines("file.txt"))
{
// now line == "account", next line == "account1"
if (line.Contains("a"))
continue;
else
// need to set that next loop will take line == "account" again
// more stuff that we don't want to execute if line.Contains("a")
}
I guess this might also helpful if someone else come
for (int i = 0; i < inventoryTimeBlocks.Count; i++)
{
if (line.Contains("a"))
//next loop take "account1";
else
{
if(i > 0)
{
i = i - 1;
continue;
}
}
}

How to go to the next value of a While loop

I have a While loop that reads a line of a file.txt. I also have a method named VerifyPhoto that returns true/false I want to go to next item of the while loop if the returned value is false. How Could I do that ? I tried break and return but it just leave all and back to the form...
while (!reader.EndOfStream)
{
if(VerifyPhoto(filed.matriculation) == false)
{
//go to the next line of the file.txt
}
}
You may want to get familiar with other control statement: continue
[EDIT] Newest version of the doc: continue, thanks Jeppe.
continue; (some more to make it 30 chars)
Depending on your actual code, maybe you could simply invert the boolean test, so you do something only if VerifyPhoto returns true:
while (...)
{
if(VerifyPhoto(filed.matriculation))
{
// Do the job
}
}
The continue statement passes control to the next iteration of the enclosing iteration statement in which it appears
while (!reader.EndOfStream)
{
if(VerifyPhoto(filed.matriculation) == false)
{
continue;
//go to the next line of the file.txt
}
}
Am I missing something in the way you are doing this?
Do you read the first line before starting the loop?
if so don't you need something like
**string line;**
while (!reader.EndOfStream)
{
if(VerifyPhoto(filed.matriculation) == false)
{
//go to the next line of the file.txt
**line = file.ReadLine();**
}
}
If you're trying to read line by line then File.ReadLines may be useful.
Also what you're looking for is the continue statement.
string myFile = #"c:\path\to\my\file.txt";
foreach(string line in File.ReadLines(myFile))
{
//Do stuff
//if(!VerifyPhoto())
// continue;
//Do other logic
}

Stop Looping C#?

How to stop my Loop if the value is already existing?
here's my code in C#...
foreach (ArrayList item in ArrData)
{
HCSProvider.NewProviderResult oResult;
oResult = oHCSProvider.CreateNewProvider(providercode, oProviderDetail)
DBInterface ProviderDetail = new DBInterface();
ProviderDetail.InsertProvider(Convert.ToInt64(providercode), Convert.ToString(oProviderDetail));
}
you can skip iteration with
continue;
and stop loop with
break;
If you are inside a loop and want to abort the loop execution and jump to the code after the loop, insert a break; statement.
If you only want to stop the current loop iteration, and continue with the rest of the loop, add a continue; statement instead.
You can stop any loop in c# by a break statement
You can write something like this:
foreach(var o in list)
{
if (o.SomeValue == 1)
{
break;
}
}
Continue, break and goto are used in C# for skipping the loop.
Continue
Skips the execution of current iteration
Continue;
break
Comes out of the loop and continues the next statement after the loop
break;
goto
is normally not recommend, but still can be used to move control out of the loop
goto Outer;
You can put a break command to exit from For Loop.
foreach(var item in items)
{
if(item == myitem)
{
break;
}
Console.WriteLine(item);
}
you can easily stop your lop on a condition with the break statement!
Small example:
var arr = new [] {1,2,3,4,5,6,7};
int temp = 0;
foreach(var item in arr)
{
temp = item +1;
if(temp == 5)
{
break;
//...
}
//do something
}

Foreach loop takes a very long time to break out of

Scraping a webpage, containing about 250 table divisions.
Using WatiN and WatinCSSSelectors
First I select all td tags with attribute 'width=90%':
var allMainTDs = browser.CssSelectAll("td[width=\"90%\"]");
Then I make a foreach loop, stick the contents of the var into a List. The int is there to check what td tag the loop is currently at.
List<Element> eletd = new List<Element>();
int i = 0;
foreach (Element td in allMainTDs)
{
eletd.Add(td);
i++;
Console.WriteLine(i);
}
It reaches the 250th tag fairly quickly. But then it takes about 6 minutes (timed with a StopWatch object) to go onto the next statement. What is happening here?
You could try this:
var eletd = new List<Element>(allMainTDs);
A foreach loop is roughly equivalent to the following code (not exactly, but close enough):
IEnumerator<T> enumerator = enumerable.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
T element = enumerator.Current;
// here goes the body of the loop
}
}
finally
{
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
The behavior you describe points to the cleanup portion of this code. It's possible that the enumerator for the result of the CssSelectAll call has a heavy Dispose method. You could confirm this by replacing your loop with something like the code above, and omit the finally block, or set breakpoints to confirm Dispose takes forever to run.
If you under .net 4.0 and you execution environment allows for parallelism, you may be should try the
Prallel.ForEach(..);

Categories

Resources