storing and reusing conditional expression - c#

I need to evaluate same conditional expression multiple times in code.
What is the best way to store and reevaluate the conditional expressions in C#
eg. I want to remove the duplication of conditional expression given in while and if without using additional function call
while(!int.tryparse(num) || num <= 0 || num > 2000)
{
num = console.ReadLine();
if(!int.tryparse(num) || num <= 0 || num > 2000)
{
console.write("There is an error in the input value");
}
}

Not sure if this is exactly what you're looking for, but one handy way to get strongly-typed (and otherwise valid) input from the user is to write a method that takes in a string prompt (which asks the user for some input) and an optional Func<int, bool> argument that returns true if the int meets some criteria. We can also have an optional error message to display if the input is incorrect.
Here's a method that I've used in the past:
public static int GetIntFromUser(string prompt, Func<int, bool> validator = null,
string error = null)
{
int result;
bool invalidInput = false;
do
{
if (invalidInput && !string.IsNullOrEmpty(error))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(error);
Console.ResetColor();
}
Console.Write(prompt);
invalidInput = true;
} while (!int.TryParse(Console.ReadLine(), out result) ||
(validator != null && !validator.Invoke(result)));
return result;
}
In use, it makes life really simple, because you never have to write the validation code again. Note that we can just write an in-line lambda expression for our validator argument:
int input = GetIntFromUser("Enter a number from 0 to 2000: ",
x => x >= 0 && x < 2000, "Invalid number, try again.");
Output
Now, if we want to use the exact same validation over and over again (in different areas of code, outside of a loop), we can extract the above method call to a Func<int> and call it whenever we want:
Func<int> ZeroTo2000 = () => Temp.GetIntFromUser("Enter a number from 0 to 2000: ",
x => x >= 0 && x < 2000, "Invalid number, try again.");
int input1 = ZeroTo2000();
int input2 = ZeroTo2000();

Extract to a separate method.
public bool IsValid(string input)
{
if (!int.TryParse(input, out var result)) return false;
return (result > 0 && result <= 2000);
}
Then you can use it like this (your original code had problems which I fixed):
while (true)
{
num = Console.ReadLine();
if (IsValid(num)) break;
Console.WriteLine("There is an error in the input value");
}

You can combine both the code for reading the input and the code that validates the input. Also, if you prefer to encapsulate the validation code within the same method, you can use delegates. See below.
Func<string,bool> InputIsInvalid = (stringNum) =>
{
int intNum;
return !int.TryParse(stringNum, out intNum) || intNum <= 0 || intNum > 2000;
};
while(InputIsInvalid(Console.ReadLine()))
{
Console.WriteLine("There is an error in the input value");
}

Create a middle exit loop with an infinite for and break to test only once:
string snum;
int num;
for (;;) {
snum = Console.ReadLine();
if (Int32.TryParse(snum, out num) && 0 <= num && num <= 2000)
break;
Console.Write("There is an error in the input value");
}

Related

How do I detect an infinite loop occuring in my code?

So my code is to check if a given number is a 'happy number'. It squares each digit of the number, adds them and continues to do so until either the result of the addition is 1 (which means it is a happy number) or until it results in a 4 (which means it is not a happy number).
What's happening is that there are many numbers which cause an infinite loop (therefore meaning they are not a happy number) and I'm wondering how I would construct my code so that it will detect when there's an infinite loop occuring? I have some ideas but all flawed.
My code is as follows:
using System;
namespace Happy_numbers_problem
{
class Program
{
static int HappyNumbers(string Number)
{
string Output = Number;
while ((Convert.ToInt32(Output) != 1) && (Convert.ToInt32(Output) != 4))
{
string Result2 = "0";
for (int Index = 0; Index < Output.Length; Index++)
{
string Character = Output.Substring(Index, 1);
int Calc = Convert.ToInt32(Character);
int Result = Calc * Calc;
//Adding Result2 and Result, then turning it into a string.
Result2 = Convert.ToString(Convert.ToInt32(Result2) + Result);
if (Index == (Output.Length) - 1)
{
Output = Result2;
}
}
}
return Convert.ToInt32(Output);
}
static void Main(string[] args)
{
Console.WriteLine("Please enter a number");
string Number = Console.ReadLine();
int Output = HappyNumbers(Number);
if (Output == 1)
{
Console.WriteLine(Number + " is a happy number");
}
else if (Output == 4)
{
Console.WriteLine(Number + " is not a happy number");
}
else
{
Console.WriteLine(Number + " is not a happy number");
}
}
}
}
The problem resides in your while condition. If your output needs to be 1 or 4 to break out of the loop and deliver the output to latter be analysed, you have to use the operator or || instead of the operator and &&.

c# do while unassigned local variable problem

I am following a c# course and trying to upgrade my user input method to check if the entered console input is an integer. I have written myself into a do while loop that I know doesn't work, but I am struggling a bit with coming up with a method that can both check for value and if the entered variable is an integer.
So what I tried here was to do-while until the user entered input is an Integer and between the min and max values. But I get stuck on result is only set to a value in the 'if' block, not the 'else' block. It won't compile unless result is set to something, unassigned variable. And I understand why, because there is a branch where I end up with a variable without value, and that won't pass in my while greater-less comparisson. You can only compare numbers, not nulls or strings.
Should I abandon the do-while loop for something more clever? Right now my 'hack' is to set result = 0 in the case that TryParse is false.
That is only useful as long as the user does not need to input 0, in which case the whole thing makes no sense any longer.
static int readInt(string prompt, int low, int high) // METHOD readInt
{
int result;
bool succes;
do
{
int temp;
string intString = readString(prompt);
succes = Int32.TryParse(intString, out temp);
if (succes)
{ Console.WriteLine("The string was a number within the limits, {0}.", intString);
result = int.Parse(intString);
}
else
{
Console.WriteLine("{0} is not a valid number between {1} and {2}", intString, low, high);
result = 0;
}
} while (!succes && (result < low) || (result > high));
return result;
}
It might be easier to just use a while (true) loop and return from inside the loop when you have a valid result. This is a structured construct known as a loop with one exit, so it's fine to use (if you're worried about structured programming).
For example:
static int readInt(string prompt, int low, int high) // METHOD readInt
{
while (true)
{
string intString = readString(prompt);
if (Int32.TryParse(intString, out var result) && (result >= low) && (result <= high))
{
Console.WriteLine("The string was a number within the limits, {0}.", intString);
return result;
}
else
{
Console.WriteLine("{0} is not a valid number between {1} and {2}", intString, low, high);
}
}
}
Note the use of a relatively recent C# feature, the ability to declare an out variable at the point of use using the var keyword - see the out var result inside the TryParse().
Or for a simpler pattern
int result;
string intString;
while (!int.TryParse(intString = Console.ReadLine(), out result) || result < low || result > high)
Console.WriteLine($"{intString} is not a valid number between {low} and {high}");
Console.WriteLine("The string was a number within the limits, {result}.");
return result;
you can change your " result = int.Parse(intString);" in the "if" with "return temp";
you already have the number from your TryParse, so you do not need to parse it again; returning inside the "if" also removes the need to assign a value to 'result' inside the "else" in fact, you don't need "result" at all)
static int readInt(string prompt, int low, int high) // METHOD readInt
{
bool succes;
do
{
string intString = readString(prompt);
succes = Int32.TryParse(intString, out int temp);
if (succes)
{ Console.WriteLine("The string was a number within the limits, {0}.", intString);
return temp;
}
else
{
Console.WriteLine("{0} is not a valid number between {1} and {2}", intString, low, high);
}
} while (!succes && (result < low) || (result > high));
}
You had a couple of bugs in the code. This works:
static int readInt(int low, int high)
{
int result;
bool success;
bool outOfLimits = false;
do
{
Console.Write("Enter a number: ");
string intString = Console.ReadLine();
success = Int32.TryParse(intString, out result);
if (!success)
{
Console.WriteLine("{0} is not a valid number.", intString, low, high);
continue;
}
outOfLimits = result < low || result > high;
if (outOfLimits)
Console.WriteLine("The string was NOT a number between {1} and {2}.", intString, low, high);
else
Console.WriteLine("The string was a number within the limits, {0}.", intString);
} while (!success || outOfLimits);
return result;
}
When code evolves like yours, it sometimes gets a bit unclear what it does as the complexity rises. Usually that's a sign that you should refactor it.
I would try to make the code clearer by moving all the checks for validity into a method by itself. Then you can do something like this.
static int readInt(string prompt, int low, int high) // METHOD readInt
{
bool valid = false;
int result = 0;
while (!valid)
{
var intString = readString(prompt);
valid = checkIfValid(intString, low, high, out result);
}
return result;
}
static bool checkIfValid(string s, int low, int high, out int result)
{
if (!Int32.TryParse(s, out result))
{
Console.WriteLine(s + " isn't an integer");
return false;
}
if (result < low)
{
Console.WriteLine("Number is too low");
return false;
}
if (result > high)
{
Console.WriteLine("Number is too high");
return false;
}
return true;
}
Try implementing the routine validating the conditions one after one (we have no need to make code too complex with !succes && (result < low) || (result > high) check):
If user input a valid integer (int.TryParse)?
If valid is it within the range?
If any validation fails keep asking user:
static int readInt(string prompt, int low, int high)
{
// Keep on looping until we return a valid result
while (true)
{
// Or
// Console.WriteLine(prompt);
// string input = Console.ReadLine();
string input = readString(prompt);
int result = 0; // initialization: let the compiler be happy
if (!int.TryParse(input, out result)) // Do we have an syntactically invalid input?
Console.WriteLine($"{input} is not a valid integer number");
else if (result < low || result > high) // If result is valid; is it out of range?
Console.WriteLine($"{input} is out of [{low}..{high}] range");
else // result is valid integer and within the ranges: time to return it
return result;
}
}

How do I make a statement follow the same "if" rules as before

I am trying to write a mini-quiz and I want the "try again" button to follow the same rules as the "if" statement as before the "else"
using System;
public class Program
{
public static void Main()
{
int x;
x = int.Parse(Console.ReadLine());
Console.WriteLine("Find a number that can be divided by both 7 and 12");
if ((x % 7 == 0) && (x % 12 == 0))
{
Console.WriteLine("well done, " +x+ " can be divided by 7 and 12");
}
else
{
Console.WriteLine("Wrong, try again.");
Console.ReadLine();
}
}
}
I want the ReadLine after the else statement to follow the same rules as the "if" statement before it but it needs a whole new statement to follow and copy-pasting the statement seems like an inefficient solution.
Normally this kind of processing is done in a while loop, which continues to loop until the user answers correctly. So the key is then to create a condition that will become false when there's a correct answer.
Notice that we also have the x variable re-assigned to the Console.ReadLine() method in the else block, otherwise we're always comparing the old value of x and the loop will never end.
For example:
bool answeredCorrectly = false;
while (!answeredCorrectly)
{
if ((x % 7 == 0) && (x % 12 == 0))
{
Console.WriteLine("well done, " + x + " can be divided by 7 and 12");
answeredCorrectly = true; // This will have us exit the while loop
}
else
{
Console.WriteLine("Wrong, try again.");
x = int.Parse(Console.ReadLine());
}
}
If you want to be really tricky about it, you could write a method that will get an integer from the user, and which takes function that can be used to validate that the input is correct (any method that takes in an int and returns a bool).
This way, you can create a validation method and pass that (along with the prompt for the user) to the method that gets an integer from the user.
Note that we're using the int.TryParse method to try to get an integer from the string input. This method is really handy because it does two things: First, it returns true if the parsing succeeds, and second, it returns the int value in an out parameter. This way we can use the return value to ensure they entered a number, and we can use the output parameter to see if the number meets our conditions:
private static int GetIntFromUser(string prompt, Func<int, bool> validator = null)
{
int result = 0;
bool answeredCorrectly = false;
while (!answeredCorrectly)
{
// Show message to user
Console.Write(prompt);
// Set to true only if int.TryParse succeeds and the validator returns true
answeredCorrectly = int.TryParse(Console.ReadLine(), out result) &&
(validator == null || validator.Invoke(result));
if (!answeredCorrectly) Console.WriteLine("Incorrect, please try again");
}
return result;
}
With this method in place, we can now call it from our main method as often as we like, with whatever validation we like, and we don't need to re-write all the looping code each time:
int x = GetIntFromUser("Enter a number that can be divided by both 7 and 12: ",
i => i % 7 == 0 && i % 12 == 0);
x = GetIntFromUser("Enter a negative number: ", i => i < 0);
x = GetIntFromUser("Enter a number between 10 and 20: ", i => i > 10 && i < 20);
You could even use it to create a number guessing game with just a few lines of code!
int randomNumber = new Random().Next(1, 101);
int x = GetIntFromUser("I'm thinking of a number from 1 to 100. Try to guess it: ", i =>
{
Console.WriteLine(i < randomNumber
? $"{i} is too low - guess a larger number."
: i > randomNumber ? $"{i} is too high - guess a smaller number." : "Correct!");
return i == randomNumber;
});
Have you considered using a while block and break; on the successful condition?
using System;
public class Program
{
public static void Main()
{
int x;
Console.WriteLine("Find a number that can be divided by both 7 and 12");
while (true)
{ //Loop the code until it is broken out of
x = int.Parse(Console.ReadLine());
if ((x % 7 == 0) && (x % 12 == 0))
{
Console.WriteLine("well done, " + x + " can be divided by 7 and 12");
Console.ReadKey(); //Pause the program so it doesnt break out immediately
break; //Break out of the while loop
}
else
{
Console.WriteLine("Wrong, try again.");
}
}
}
}

Implementing Try Catch for no input and invalid input

I want to do this because I would like to block inputs that will crash my program. I tried doing it like this but I get the errors use of unassigned parameter total and the out parameter totalstring and total must be assigned before control leaves current method.
private static void Start(out String totalString, out int total)
{
Console.WriteLine("How Many ? (2-4)");
Console.WriteLine("");
try
{ totalString = Console.ReadLine();
total = int.Parse(totalString);
}
catch
{
Console.WriteLine("");
}
bool flag = false;
if ((total <= 1) || (total > 4)) //loop to reject invaid input
while (flag == false)
{
if ((total <= 1) || (total > 4))
{
Console.WriteLine("Invalid input. How many?");
totalString = Console.ReadLine();
total = int.Parse(totalString);
Console.Clear();
}
else if ((total >= 2) || (total <= 4))
{
flag = true;
}
}
Console.Clear();
Console.WriteLine("Player Numbers :" + total);
Console.WriteLine();
players = new Player[total];
}
}
}
Sorry about that :)
I'd rather use TryParse instead of Parse:
Terse:
int total;
do {
Console.WriteLine("How Many ? (2-4)");
}
while (!(int.TryParse(Console.ReadLine(), out total) && (total >= 2) && (total <= 4)))
Talkative:
int total;
Console.WriteLine("How Many ? (2-4)");
while (true) {
if (!int.TryParse(Console.ReadLine(), out total)) {
Console.WriteLine("Invalid input. How many?");
else if ((total < 2) || (total > 4)) {
Console.WriteLine("Invalid range. How many?");
else
break;
}
When you have a method that has out parameters, then you must always assign a value to them, whatever path your code takes. This is what that error message is trying to tell you.
When you have
try
{ totalString = Console.ReadLine();
total = int.Parse(totalString);
and "Console.ReadLine()" throws an error, then both totalString and total are not assigned. Similarly, when the ReadLine succeeds, but the int.Parse fails, then total is not assigned.
Simple solution: assign default values at the start of the method:
totalString = null;
total = 0;
These will be overwritten when everything works out.
There are two improvements you can make here:
1 Get rid of the out parameters and return the player array, rather than having a void method.
2 Use a do while loop instead of the current code:
private static IEnumerable<Player> Start()
{
do
{
Console.WriteLine("How Many ? (2-4)");
Console.WriteLine("");
try
{
var totalString = Console.ReadLine();
var total = int.Parse(totalString);
if (total >= 1 && total <= 4)
{
Console.WriteLine("Number of players :" + total);
return new Player[total];
}
}
catch
{
Console.WriteLine("Invalid input.");
}
} while (true)
}
You're getting this error because total is never assigned to if int.Parse() throws an exception but you are using it anyways after the catch block.
To avoid this, check total for null.
Dmitry Bychenko provided you with a pretty neat alternative so I'm just going to point out some small things in your code.
Console.ReadLine() already is a string, this would work:
total = int.Parse(Console.ReadLine);
You check total twice, once in the outer if block and again in the while loop. You don't have to do that.
Once you get to the second parse attempt within the loop and enter something invalid, an exception will be thrown but you don't handle it.
For your own sake, format your code.
Try to avoid unnecessary exceptions. If an exception is thrown, the application freezes for a few seconds which neither looks good nor is it fun to use. TryParse for example returns false if the parse attempt fails.

How to validate user input for whether it's an integer?

It tells me that it can't convert int to bool.
Tried TryParse but for some reason the argument list is invalid.
Code:
private void SetNumber(string n)
{
// if user input is a number then
if (int.Parse(n))
{
// if user input is negative
if (h < 0)
{
// assign absolute version of user input
number = Math.Abs(n);
}
else
{
// else assign user input
number = n;
}
}
else
{
number = 0; // if user input is not an int then set number to 0
}
}
You were probably very close using TryParse, but I'm guessing you forgot the out keyword on the parameter:
int value;
if (int.TryParse(n, out value))
{
}
Just use this:
int i;
bool success = int.TryParse(n, out i);
if the parse was successful, success is true.
If that case i contain the number.
You probably got the out argument modifier wrong before. It has the out modifier to indicate that it is a value that gets initialized within the method called.
You can try with some simple regular expression :
bool IsNumber(string text)
{
Regex regex = new Regex(#"^[-+]?[0-9]*\.?[0-9]+$");
return regex.IsMatch(text);
}
private void SetNumber(string n)
{
int nVal = 0;
if (int.TryParse(n, out nVal))
{
if (nVal < 0)
number = Math.Abs(nVal);
else
number = nVal;
}
else
number = 0;
}
There are a lot of problems with this code:
Using VB-style line comments (') instead of C# slashes
Parse for integer returns an int and not a bool
You should use TryParse with an out value
h does not seem to be valid at all. Is it a type for n?
There are variables that do not seem to be defined in function scope (number) are they defined at class scope?
But try this:
private void SetNumber(string n)
{
int myInt;
if (int.TryParse(n, out myInt)) //if user input is a number then
{
if (myInt < 0) //if user input is negative
number = Math.Abs(n); //assign absolute version of user input
else //else assign user input
number = n;
}
else number = 0; //if user input is not an int then set number to 0
}
You could try something like below using int.TryParse..
private void SetNumber(string n)
{
int parsed = -1;
if (int.TryParse(n, out parsed)) //if user input is a number then
...
The reason there are complaints that it cannot convert an int to a bool is because the return type of int.Parse() is an int and not a bool and in c# conditionals need to evaluate bool values.
int.Parse will give you back an integer rather than a boolean.
You could use int.TryParse as you suggested.
int parsedValue;
if(int.TryParse(n, out parsedValue))
{
}
Well for one thing the inner if statement has an 'h' instead of an 'n' if(h < 0). But TryParse should work there assuming that 'number' is a class variable.
private void SetNumber(string n)
{
int temp;
bool success = Int32.TryParse(n, out temp);
// If conversion successful
if (success)
{
// If user input is negative
if (temp < 0)
number = Math.Abs(temp); // Assign absolute version of user input
else // Assign user input
number = temp;
}
else
{
number = 0;
}
}
int.Parse will convert a string to an integer. Current you have it within an if statement, so its treating the returned value of int.Parse as a bool, which its not.
Something like this will work:
private void SetNumber(string n)
{
int num = 0;
try{
num = int.Parse(n);
number = Math.Abs(num);
}catch(Exception e){
number = 0;
}
}
I did this in the simplest way I knew how.
static void Main(string[] args)
{
string a, b;
int f1, f2, x, y;
Console.WriteLine("Enter two inputs");
a = Convert.ToString(Console.ReadLine());
b = Console.ReadLine();
f1 = find(a);
f2 = find(b);
if (f1 == 0 && f2 == 0)
{
x = Convert.ToInt32(a);
y = Convert.ToInt32(b);
Console.WriteLine("Two inputs r number \n so tha additon of these text box is= " + (x + y).ToString());
}
else
Console.WriteLine("One or tho inputs r string \n so tha concadination of these text box is = " + (a + b));
Console.ReadKey();
}
static int find(string s)
{
string s1 = "";
int f;
for (int i = 0; i < s.Length; i++)
for (int j = 0; j <= 9; j++)
{
string c = j.ToString();
if (c[0] == s[i])
{
s1 += c[0];
}
}
if (s==s1)
f= 0;
else
f= 1;
return f;
}

Categories

Resources