This is my first time using the enumerator interface.
I am Trying to look threw a stack to find next occurrence of a string.
The loop is suppose to loop threw my tags stack and find out if a tag inside my stack is a tag i was looking for. Once the stack gets to the last tag in the stack it crashes and issues the error in the title. The last tag in the list also happens to be the first match for lookforthisTag string variable. I want the while look to exit when the if statement finds a match or when all stack items have been compared.
/*find next opening tag in stack */
int I = 1;
var enumerator = tags.GetEnumerator(); /// create a enumerator variable
/// move to the next tag in stack
while ( enumerator.MoveNext() != false || found == true || I <= countofTags)
{
htmlTags currentTag = enumerator.Current; // this line causes error.
if (currentTag.open_tag == lookforthisTag)
{
found = true;
}
I++;
}///End while.
This line
while ( enumerator.MoveNext() != false || found == true || I <= countofTags)
will execute the following logic
Does the enumerator returns true? If yes enter the loop else check
next condtion
Is found == true? If yes enter the loop, else check the next condition
Is I <= countofTags? If yes enter the loop, else exit the loop
As you can see even when the enumerator return false it enters the loop because at that point found is true, but inside the loop you call enumerator.Current and this triggers the error message.
Probably you want
while ( !found && enumerator.MoveNext() && I <= countofTags)
Consider that a normal foreach loop would do the same
htmlTags found = null;
foreach(htmlTags currentTag in tags)
{
if (currentTag.open_tag == lookforthisTag)
{
found = currentTag;
break;
}
}
if(found != null)
{
// got it...
}
or just using Linq
htmlTags found = tags.FirstOrDefault(x => x.open_tag == lookforthisTag)
if(found != null)
{
// you have found your tag.
}
I want also to mention the fact that your I <= countOfTags logic
doesn't seem to have any utility in the code shown. The variable I will be always equal to the countOfTags (or just simply equal to tags.Count) because you don't break the loop and continue till the end of the enumeration. If you want to know the 'position' of the found tag, just increment it.
I would rewrite your while condition like this:
while ( enumerator.MoveNext() && !found && I < countofTags)
Or just use linq:
tags.Single (currentTag == currentTag.open_tag == lookforthisTag)
The condition in the while will be true even if enumerator.MoveNext() will be false, because of the or conditions.
It can probably be fixed with changing the condition and also using break to get out of the loop.
like this:
while ( enumerator.MoveNext() && I <= countofTags)
{
htmlTags currentTag = enumerator.Current; // this line causes error.
if (currentTag.open_tag == lookforthisTag)
{
found = true;
break;
}
I++;
}///End while.
But, i wouldn't go this way in the first place.
Use LINQ:
var myItem = tags.FirstOrDefault(currentTag=> currentTag.open_tag == lookforthisTag);
Related
I am wondering if there is a way to check multiple while loop conditions using the same variable. That's a bit vague, but this example should clear it up:
while (myFunction(x) == 0 || myFunction(x) == 13639 || myFunction(x) == -4261.9583)
{ x++; }
Is it possible to only evaluate myFunction(x) once per loop while checking the three conditions, so that the function doesn't have to run three separate times for a result that is the same each time?
I am doing this for optimization/efficiency purposes. myFunction() could be a pretty time-consuming function, so I want it to run the minimum amount of times necessary.
Typically I would define the value of myFunction(x) before I start the while loop, but in this case, the value of myFunction(x) will be changing as the loop goes through each iteration, since the value of x will be changing.
Yes, this can be done:
double result;
while ((result = myFunction(x)) == 0 || result == 13639 || result == -4261.9583)
{ x++; }
Three options:
Do it backwards
Check a list for the result rather than checking the result against the list.
var list = new float[] { 0F, 13639F, -4261.9583F );
while (list.Contains(myFunction(x))
{
x++;
}
Write a function
Extracting the logic to another function is always a nice way to break down the problem.
bool IsValid(float input)
{
var result = myFunction(input);
return (result == 0 || result == 13639 || result == -4261.9583);
}
while (IsValid(x))
{
x++;
}
Use while(true)
Whenver the condition of a while loop is complicated, a common option is to remove the check from the () and put it in the {} instead. When you do this, use while (true).
while (true)
{
var result = myFunction(x);
if (result != 0 && result != 13639 && result != -4261.9583) break;
x++;
}
You can do this simply by moving the check into a separate method, which takes the return value of the function as parameter, and then performs the 3 checks on the value directly and returns a boolean accordingly.
Assuming the function returns a int typed value this may for example look something like this:
bool CheckResultValue(int value) {
return value == 0 || value == 13639 || value == -4261.9583;
}
Then your while loop could look something like this:
while (CheckResultValue(myFunction(x)))
{ x++; }
I have the following while statement -
while ((!testString.Contains("hello")) && (NewCount != OldCount) && (attemptCount < 100))
{
//do stuff (steps out too early)
}
This is stepping out of the statement even though all the conditions have not been met.
I have tried to reduce it like -
while (!testString.Contains("hello"))
{
// this works and steps out when it should
}
And this steps out when hello is present for example. I also tried changing this to an OR statement which reversed the problem to never stepping out the statement.
Addint the && (NewCount != OldCount) && (attemptCount < 100)) conditions is causing this behaviour how can I resolve this?
This is stepping out of the statement even though all the conditions
have not been met.
To achieve that you need to specify logical OR (||).
For example:
while ((!testString.Contains("hello")) || (NewCount != OldCount) || (attemptCount < 100))
{
//while at least one those conditions is true, loop will work
}
Which means that inside loop you need to introduce security checks, where required, for conditions which are not more true, while loop is still executing.
As an addition to TigranĀ“s answer. Often (in order to avoid mess with the complex condition) it could be useful to push the condition into the loop:
while (true) { // loop forever unless:
if (testString.Contains("hello")) // ...test string contains "hello"
break;
if (NewCount == OldCount) // ...counts are equal
break;
if (attemptCount >= 100) // ... too many attempts
break;
// ...it's easy to add conditions (as well as comment them out) when you have them
// Loop body
}
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;
}
}
}
I know this is a very newbie C# question but I am implementing a small program which does the following:
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
bool isRun = false;
int number = 0;
while (isRun = (true) && number < 3)
{
++number;
Console.WriteLine("Number = {0}", number.ToString());
Console.WriteLine();
}
Console.WriteLine(isRun.ToString());
Console.ReadLine();
}
}
}
At the end of the while loop, I would have expected the bool value to be true, but is is printed to be false. Why is that? Is this different from C++ where I would have done something like and the same thing in C# is giving me false
while(number<3)
{
is = true;
}
if(is){
cout<<true;
}
The reason you're seeing this behavior is due to the operator precedence involved. Here the && binds more strongly than = so the code in the loop is actually bound as the following
while (isRun = (true && number < 3)) {
...
}
Once number > 3 the && expression is false and is assigned into the isRun value and simultaneously terminates the loop. Hence once the loop exits you will see isRun as false
To get the behavior you are looking for you will need to manually correct the precedence with parens.
while ((isRun = (true)) && number < 3) {
...
}
Note: In general, as #Servey pointed out, the assignment of locals to expressions inside the loop predicate is considered bad practice. Many C# users would actually be surprised that code compiles at all because they've been conditioned to only use == in loops.
It's more idiomatic to simply set isRun to true on the first line of the loop for this pattern.
while (number < 3) {
isRun = true;
...
}
The problem is that you have set you boolean variable to false and without assigning it back to true, in while loop you are matching it against the value true, thus it fails in every case.
I'm trying to calculate the number of success cases within a recursive function in C#, but I'm astonished by the fact that my variable is shared between all the function calls!
[update 2]
More than strange this time. doing so
i = i + validTreesFun(tree.Nodes, newWords.ToList()) ;
resets i to 0
doing this
i = validTreesFun(tree.Nodes, newWords.ToList()) + i ;
gives some results (I'm not sure if it's correct)
[updated : the full code]
public static int validTreesFun(List<Tree<char>> nodes, List<string> words)
{
int i = 0;
if (nodes == null && (words == null || words.Count == 0 || (words.Count == 1 && words.First() == "")))
return 1;
else
if (nodes == null)
return 0;
foreach (Tree<char> tree in nodes)
{
var validWords = words.Where(w => w.ToCharArray()[0] == tree.Root)
.Select(w => w);
if (validWords.Count() == 0)
return 0;
else
{
var newWords = validWords.Select(w => join( w.ToCharArray().Skip(1).ToArray()));
i += validTreesFun(tree.Nodes, newWords.ToList());
}
}
return i;
}
when debuging the variable i take the value 1 but it resets to 0 on the next iteration!!
despite the use of
i = i + ....
What is the problem in that piece of code?
Thank you
if (validWords.Count() == 0)
return 0;
Should be
if (validWords.Count() == 0)
continue;
Also, in general, I personally think it is nicer looking to only send in one element at a time to a recursive function.
public static int validTreesFun(Tree<char> node, List<string> words)
That way you don't get the same kind of mistake like above. Finally, a minor note.
w => w.ToCharArray()[0] == tree.Root
can be written as
w => w[0] = tree.Root
No local variables are not at all shared between recursive calls, you should consider some other design problem, inside and after your foreach loop, I dont see any return statements, can you post full code.
Ok, in debugging you will always observe i's current method's value, debugging is not good in recursive functions, its little hard to understand, you will have to move your control down in Call Stack in order to actually observe value of earlier caller of current function.
I would advice you to output Trace or on log file with your level of node, that will help you actual debugging.
Please use TRACE Statement as follow..
Trace.WriteLine(string.Format("{0},{1}",tree.Name,i));
Local variables are not being shared.
What you are seeing (the reset to 0) is the value of i in the (recursively) called function validTreesFun (i gets set to 0 at the start of the function).
Just looking at your code, I think a possible bug might be in someTestHere - if that is never true, then i will stay 0 in the outer scope. Otherwise it should increment by 1 for each true test.
When you are in debug mode, you indeed see that the i is reseted for the call but remain to the wanted value for the caller. Eg , the stack :
validTreesFun --i = 0 for this one
validTreesFun --i = x for this one, but if you do not go trow the calling stack, you will see 0, which is the good value for the top of the stack