I'm using C# to compare data in different sheets in excel, and need to write the pass/fail result into the excel as well.
But for this part code, I only get the result of 'fail' in the excel, even the result should be 'pass'.
Anyone could have a look please?
for (i = 1; i <= baseline.GetLength(0); i++)
for (j = 1; j <= baseline.GetLength(1); j++)
{
if (baseline[i, j]?.ToString() == result_PriceUpdate[i, j]?.ToString()) goto EndofLoop1;
if (baseline[i, j]?.ToString() != result_PriceUpdate[i, j]?.ToString()) goto EndofLoop2;
}
EndofLoop1:
result_file.WriteResultToExcel("Result Summary", 2, 2, "pass");
EndofLoop2:
result_file.WriteResultToExcel("Result Summary", 2, 2, "fail");
There's no way the code in the question will ever look at more than the first cell.
The only difference between the two if() conditions is one uses == while the other uses !=; one of those conditions will always be true. Thus the very first cell will always break out of the loop. It's the same as if you had written this code, with no loop at all:
if (baseline[1, 1]?.ToString() == result_PriceUpdate[1, 1]?.ToString())
goto EndofLoop1;
if (baseline[1, 1]?.ToString() != result_PriceUpdate[1, 1]?.ToString())
goto EndofLoop2;
EndofLoop1:
result_file.WriteResultToExcel("Result Summary", 2, 2, "pass");
EndofLoop2:
result_file.WriteResultToExcel("Result Summary", 2, 2, "fail");
Maybe you're relying on the ?. null conditional operator to create comparisons with null, with the idea this will behave the same as it does in SQL, where comparing a value with null could produce false for both the != and == conditions. That won't happen here.
Worse, the jump to EndOfLoop1 doesn't end the code. The EndOfLoop2 section is still part of the method, and it will also run. Once the second section runs, it replaces the work from the first section. Even when you pass, the result you'll see in the file is still "fail".
More than that, if somehow no condition in the loop is ever true, both named sections would still run after the loop finished.
Better practice here is simply don't use goto. There's no need, and it clearly confused things. Instead, set a string variable to either "pass" or "fail" and change i and j to int.MaxValue so the loop exits right away naturally. Then only have one WriteResultToExcel() to write out the string variable.
The obvious mistake with the loop means the code in the question is unfortunately not clear enough to determine your real intent. I will suggest a solution based on the idea you want to pass only if all cells pass, and if any cells fails that will fail the entire data set:
string result = "pass";
for (i = 0; i < baseline.GetLength(0); i++)
for (j = 0; j < baseline.GetLength(1); j++)
{
if (baseline[i, j]?.ToString() != result_PriceUpdate[i, j]?.ToString())
{
result = "fail";
i = int.MaxValue;
j = int.MaxValue;
}
}
result_file.WriteResultToExcel("Result Summary", 2, 2, result);
I also have a question about starting with 1, rather than 0. C# arrays start at 0, but you never try to check the 0 positions for either dimension of the arrays, and this seems like a clear mistake.
Finally I got the issue fixed. The loop was incorrect:
for (i = 1; i <= baseline.GetLength(0); i++)
for (j = 1; j <= baseline.GetLength(1); j++)
It should be :
for (i = 1; i < baseline.GetLength(0); ++i)
for (j = 1; j < baseline.GetLength(1); ++j)
Related
Why doesnt this for loop work while the while loop does
for (int i = 0; i > 10; i++)
{
Console.WriteLine(i);
}
int j = 1;
while(j != 11)
{
Console.WriteLine(j);
j++;
}
It's easy to mix up comparers. A good way to remember for me is the heart. <3 because I know that's read as "Less than three".
It's easy to get confused when starting out, you just mixed up the condition.
As of why your for does not work is because it starts with i = 0 then checks if if 0 is greater than 10 which is not that's why it will not excute the loop body and terminates the loop.
In your while loop, initially j = 1 then while checks if 1 is not equal to 11, which is true so loop body will execute until j is not equal to 11.
I'm pretty new to C# and want the users to be able to write in 5 numbers between 1 to 25. The issue I'm having is that I don't want the user to type a number over 25 or a number below 1.
Also this is a task for my studies and my teacher want us to use arrays so I'm not allowed to use List.
int[] usernum = new int[4];
for (int i = 0; i < usernum.Length; i++)
{
usernum[i] = Convert.ToInt32(Console.ReadLine());
}
Ok, to start off, some annotations to your code:
int[] usernum = new int[4]; // should be: new int[5];
for (int i = 0; i < usernum.Length; i++)
{
usernum[i] = Convert.ToInt32(Console.ReadLine()); // use int.TryParse instead
}
Now, I don't want to just give you the code, since this should obviously be a learning experience.
What you need to do, though is integrate a "validation" cycle. That means:
Read in string from user
Try to parse string to number
If that fails: back to 1.
Check if number < 1 or > 25
If so: back to 1.
If you are here, you passed both checks and can
set usernum[i] = number
Next "i"
Obviously, there are some slight variations in how you twist and turn your checks and arrange loops which are equally valid.
For example: You can decide if you want to check if number is inside bounds or if you want to check if the number is outside bounds and jump or not jump accordingly ...
Why int.TryParse instead of Convert.ToInt32?
There are some rule of thumbs that can spare you from severe headaches:
"Never trust user input"
"Do not use exceptions for control flow"
Using Convert here, breaks both.
For one, Convert.ToInt32 throws if the string does not represent an integer value (chars other than +-0..9, value > int.Max or < int.Min). So in using it, you trust the user to type in a valid integer. Not a good idea.
Then, it throwing means: the case, that a user (maybe just made a typo) did not provide valid input is controlling your flow to error handling. But this case is not at all "exceptional". In fact, you should expect it. int.TryParse makes this possible, in that it returns you a flag (boolean) that informs you about success or failure of the conversion attempt (instead of throwing).
Though I would recommend you to learn if else loop first https://www.w3schools.com/cs/cs_conditions.asp
here is the code if needed
int[] usernum = new int[4];
for (int i = 0; i < usernum.Length; i++)
{
var result = Console.ReadLine();
int currentResult;
if (!int.TryParse(result, out currentResult))
{
Console.WriteLine("Invalid input - must be a valid integer value");
i--;
continue;
}
if(currentResult < 1 || currentResult > 25)
{
Console.WriteLine("Invalid input - must be between 1 & 25");
i--;
continue;
}
usernum[i] = currentResult;
}
for-loop might not be the ideal solution for this use-case where you need to conditionally increment the index.
This should do the trick:
int[] userNumbers = new int[5];
int i = 0;
while (i < userNumbers.Length)
{
string rawInput = Console.ReadLine();
bool isNumberValid = int.TryParse(rawInput, out int inputNumber); // as suggested by #Fildor
if(isNumberValid && inputNumber >= 1 && inputNumber <= 25) // increment counter only if 1 <= input <= 25
{
userNumbers[i] = inputNumber;
i++;
}
}
So, I have this for loop:
double spec = 0, tot = 0;
for (int i = 0; i < omega_algo.Length; i++)
{
if (omega_algo[i] > 0)
spec = Math.Sqrt(omega_algo[i]);
else
spec = 0;
tot += spec;
}
Where myArray.Length = 50.
I get an IndexOutOfRangeException while debugging and see that i is 50.
So, the for loop is entering when it shouldn't ( i < myArray.Length is false )!
This exception only occurrs ocasionally, which makes it even more weird.
Does someone have an explanation/fix for this? Am I missing something or could this be a weird Visual Studio bug?
EDIT:
I've edited the for loop to show the code.
No i is being incremented and omega_algo array is not changing at all.
EDIT:
Based on the comments below, I wrote a sample app, and your code should work as is.
If your array really does have a length of 50, then the value of i will never be 50. The only way this would be possible is if you are changing the value of i inside the loop.
Can you provide more code to show some context of how/where this is being used? How the array is being defined etc?
Your code should work if executed on a single thread. Do you have any thread or asynchrone jobs that are editing the array?
If so, just lock the array before accessing it and before editing it.
lock(myArray)
{
for (int i = 0; i < myArray.Length; i++)
{
int someVar = myArray[i]; //this is where exception is thrown when i=50
}
}
EDIT:
Since omega_algo array is not changing at all, this is not a threading issue.
I've been playing space engineers which has been epic since they added in-game programming, I'm trying to make a gps auto-pilot navigation script and have to get the block positions finding the blocks by name looking for a smaller string within their bigger string name. I wrote this method to find a small string (word) in a larger string (name of the block):
bool contains(string text, string wordInText)
{
char[] chText = text.ToCharArray();
char[] chWord = wordInText.ToCharArray();
int index = 0;
for(int i = 0 ; i < chText.Length - chWord.Length ; i++)
for(int j = 0; j < chWord.Length;j++,index++)
if (chWord[0] == chText[i])
index = i;
else if (chWord[j] == chText[index]){}
else if (index == chWord.Length-1)
return true;
else break;
return false;
}
Am I even doing it right, should I be doing it another shorter way?
This is simple with .Contains() which returns a bool.
text.Contains(wordInText);
If you simply want to check if a string contains an other string, then you can use string.Contains, the string class already provides a bunch of methods for string operations.
As already mentioned, the String class already has a Contains method that should give you what you need.
That said, your code doesn't work. I can see where you're going with it, but it's just not going to work. Stepping through it in a proper dev environment would show you why, but since this is more in the way of a script that's probably not an option.
So... the basic idea is to iterate through the string you're searching in, looking for matches against the string your searching. Your outer for statement looks fine for this, but your inner statements are a bit messed up.
Firstly, you're doing the first character check repeatedly. It's wasteful, and misplaced. Do it once per iteration of the outer loop.
Second, your exit condition is going to fire when the first character of wordInText matches the characters at index wordInText.Length in text which is not apparently what you want.
In fact you're all tripped up over the index variable. It isn't actually useful, so I'd drop it completely.
Here's a similar piece of code that should work. It is still much slower than the library String.Compare method, but hopefully it shows you how you might achieve the same thing.
for (int i = 0; i <= chText.Length - chWord.Length; i++)
{
if (chText[i] == chWord[0])
{
int j;
for (j = 0; j < chWord.Length; j++)
{
if (chText[i + j] != chWord[j])
break;
}
if (j == chWord.Length)
return true;
}
}
return false;
I am trying to get my loop to stop when i is equal to the loopEnd variable. Here is the code:
for (int i = loopStart; i < loopEnd; i++)
At the moment it stops when i is greater than loopEnd, but the program won't run if I replace < with =, and it won't work if I use ==.
No, currently it will stop when i is equal to loopEnd (because then i is not less than loopEnd). If you want it only stop when i is greater than loopEnd, use <= instead:
for (int i = loopStart; i <= loopEnd; i++)
Note that this approach has problems if loopEnd is int.MaxValue - you'll loop forever, because when i is incremented, it will become int.MinValue which is again less than loopEnd (unless you're in a checked context, in which case an exception will be thrown).
This may well not be an issue for you, but it's worth being aware of.
for (int i = loopStart; i <= loopEnd; i++)
//^ apply less or equal operator
for (int i = loopStart; i <= loopEnd; i++)
Is that what you want?
Use <= with loopEnd in your loop. Like;
for (int i = loopStart; i <= loopEnd; i++)
Use i != loopEnd. This condition indicates when to enter the loop, rather than when to stop entering.
As Chris mentions in his comment, it's mostly better to use <=, as you might increment i within the body and skip loopEnd.