Case/switch statements c#? - c#

I haven't a living clue how to write this in c#. I know how to do it in Delphi.
This is how I would do it in Delphi:
Case Total of
80..100 : ShowMessage ('You got an A!');
60..79 : ShowMessage ('You got a B!');
50..59 : ShowMessage ('You got a C!');
40..49 : ShowMessage ('You got a D!');
0..39 : ShowMessage ('You got an E...');
end;
I have read tutorials for this, but I wouldn't know how to use/write it in the way I need it.
Here's my version in c#:
switch (Total) //'Total' is a bunch of Integers divided together to get a Percentage
{
case 80..100: //Where 80% to 100% would achieve an A
{
MessageBox.Show("You got an A!");
}
case 60..79: //Where 60% to 79% would achieve a B
{
MessageBox.Show("You got a B!");
}
Is this possible?
Thanks.

To express a range in a switch / case statement in C# you have to manually list out the cases
switch (Total) {
case 80:
case 81:
...
case 100:
MessageBox.Show("you got an A");
break;
...
}
For large ranges such as this though it may be better to just use a series of if statements
if (Total >= 80 && Total <= 100) {
MessageBox.Show("you got an A");
} else if (Total >= 70) {
MessageBox.Show("you got a B");
}

C# does not have a particularly flexible switch statement. This is intentional, options are limited to ensure that code generation is fast. C# has never been a language that hides execution cost. Runtime implementation is through a jump table, indexed by the switch() expression. Very fast, but not very flexible.
The alternative is an explicit if/else if chain. The exact same code that a VB.NET or Delphi compiler generates, but written by hand. Not terribly pretty, but effective enough:
if (Total < 0 || Total > 100) throw new ArgumentException("Not a valid grade");
if (Total >= 80) ShowMessage ('You got an A!');
else if (Total >= 60) ShowMessage ('You got a B!');
else if (Total >= 50) ShowMessage ('You got a C!');
else if (Total >= 40) ShowMessage ('You got a D!');
else ShowMessage ('You got an E...');
This now also shows the cost associated with the code, there can be up to 6 comparisons on the Total value. If speed is essential and the range is limited then consider switching to a lookup table, a Dictionary<>. Not necessary here, ShowMessage() is an expensive method.

If it is supposed to be a switch then it should be like this:
switch(Total)
{
case 100:
case 99:
//...
case 80:
MessageBox.Show("You got an A!");
break;
case 79:
// ...
}
If it is okay to use if-statements I would recommend to do it like this:
if (Total < 0)
{
}
else if (Total < 40)
MessageBox.Show("You got an E...")
else if (Total < 50)
MessageBox.Show("You got a D!");
else if (Total < 60)
// etc.
Hop you could use this answer.

AFAIK you can't do it natively in C# but if you want to do it with a switch, like you stated in your question, there is a workaround for that (for fixed ranges).
Considering your interval of 20 by 20:
int interval= (value-1) / 20;
switch (interval)
{
case 0: // 1-20
//Do stuffs
break;
case 1: // 21-40
//Do stuffs
break;
// and so on
}

A solution to solve your problem is to do it like this.
switch (Total)
{
case 1: case 2: case 3:
// Do Something
break;
case 4: case 5: case 6:
// Do Something
break;
default:
// Do Something
break;
}
Multiple Cases in Switch:

What about this?:
var s = "EEEEDCBBAAA";
var result = s[Total/10];
MessageBox.Show("you got a " + result);
Because Switch Statements Smells :)
Update
Didn't realize the a / an difference, but:
MessageBox.Show(string.Format("you got a{0} {1}",
result == "A" || result == "E" ? "n" : "",
result));

You could use a switch/case statement by creating a very long case statement or an extension method that turned a range of numbers into a constant. But it's probably easier to use an if/else block.
Personally, I like the readability of Enumerable.Range slightly over >= and <=. However, it is a slower operation because you're creating an enumerable of ints everytime you do a comparison. You'll probably on notice performance issues when you get in the tens of thousands of grads though.
if(Enumerable.Range(80,100).Contains(Total))
{
MessageBox.Show("You got an A!");
}
else if(Enumerable.Range(60, 79).Contains(Total))
{
MessageBox.Show("You got a B!");
}
else if(Enumerable.Range(50, 59).Contains(Total))
{
MessageBox.Show("You got a C!");
}
else if(Enumerable.Range(40, 49).Contains(Total))
{
MessageBox.Show("You got a D!");
}
else if(Enumerable.Range(0, 39).Contains(Total))
{
MessageBox.Show("You got an E...");
}

Use an action lookup (like a command pattern)
static void Main(string[] args)
{
var theGrade = 89;
var gradeLookup = new Dictionary<Func<int, bool>, Action>
{
{ x => x >= 90, () => ShowMessage("You got an A!") },
{ x => x >= 80 && x < 90, () => ShowMessage("You got an B!") },
};
gradeLookup.First(x => x.Key(theGrade)).Value();
Console.ReadKey();
}
static void ShowMessage(string msg)
{
Console.WriteLine(msg);
}
You can also simply divide by 10 to reduce the checks, but this would only work for some college scales:
static void Main(string[] args)
{
var theGrade = 80;
switch (theGrade / 10)
{
case 10:
case 9:
ShowMessage("You got an A");
break;
case 8:
ShowMessage("You got a B");
break;
case 7:
ShowMessage("You got a C");
break;
case 6:
ShowMessage("You got a D");
break;
default:
ShowMessage("You got a F");
break;
}
Console.ReadKey();
}

What about this code:
private string GetTotalCode(int total) {
if (Total >= 80 && Total <= 100)
return "A"
if ...
}
and then simplify switch:
switch (GetTotalCode(Total)) {
case "A":
MessageBox.Show("you got an A");
break;
...
}

Related

Switch Event Being Skipped in Debug

I have a WPF application which has random chances of random events occurring. I have a switch statement like so which switches a random number:
(property)
static Random RandomObject { get; set; } = new Random();
...
RandomObject = new Random();
switch (RandomObject.Next())
{
case 1 when RandomObject.Next(1, 3) == 2:
// a
case 1 when RandomObject.Next(1, 13) == 2:
// b
break;
}
For some reason, in debug mode, the whole switch is being skipped completely. Could someone tell me what I'm doing wrong or how I could possibly make it so it does work?
EDIT: Okay can someone tell me how to fix this instead because I remember coming up with something similar that does what I want to do and it did work but the problem is my hard drive crashed so I lost all of my data
Would this be possible?
switch(RandomObject)
{
case 1 when RandomObject.Next(1,3) == 2:
//do stuff
break;
}
I will run tests to try to show you what's going wrong. Let's take this code, which is similar to your own:
int acount = 0, bcount = 0;
var r = new Random();
for(var i = 0; i < 1_000_000_000; ++i) // 1 billion iterations
{
switch (r.Next())
{
case 1 when r.Next(1, 3) == 2:
++acount;
break;
case 1 when r.Next(1, 13) == 2:
++bcount;
break;
}
}
Console.WriteLine($"a case hit {acount} times");
Console.WriteLine($"b case hit {bcount} times");
The output is:
a case hit 0 times
b case hit 0 times
Now, let's try shrinking up your range on your switch statement:
// ...
switch (r.Next(1, 20))
{
// ...
Your results are now:
a case hit 26313397 times
b case hit 2191910 times
So what we are trying to tell you in the comments is Random.Next() returns a value in the range of [0, 2147483647], which is near unlikely to ever return the value of 1, which is what your switch cases require to continue. By changing your range with much more reasonable values, your chances increase dramatically and is more than likely what you want.

Why does int seem to default to 50 rather than 0 in C#?

My goal here is to ask the user to which of the three pre-determined ascii art picture they would like to print and how many times they would like to print it. My problem is that it print about 50 times more than whichever number was chosen. I tried converting the print variable, but that didn't work. I'm fairly new to C# so I apologize for any major, basic errors.
Console.WriteLine("Would you like to print picture 1, 2, or 3?");
int print = 0;
string choice = "";
while (choice != "end")
{
choice = Console.ReadLine();
switch (choice)
{
case "1":
Console.WriteLine("How many times would you like to print it");
print = Convert.ToInt32(Console.ReadLine());
while (print > 10)
{
Console.WriteLine(cocaCola);
print -= 1;
}
break;
case "2":
Console.WriteLine("How many times would you like to print it");
print = Convert.ToInt32(Console.ReadLine());
while (print > 10)
{
Console.WriteLine(beam);
print -= 1;
}
break;
case "3":
Console.WriteLine("How many times would you like to print it");
print = Convert.ToInt32(Console.ReadLine());
while (print > 10)
{
Console.WriteLine(liberty);
print -= 1;
}
break;
default:
Console.WriteLine("You chose nothing");
break;
}
Console.WriteLine("Choose again, or type \"end\" to exit");
It's not printing 50 more times; it's printing exactly 48 more times.
You're reading a character and assigning its unicode value to an integer. For example, user types '1', the character 1. Its Unicode value is 49. You assign 49 to your int print, and there you are. A character is really a small or smallish integer, which is essentially an index into a table of characters somewhere.
In Unicode, as in ASCII, '0' is decimal 48, '1' is decimal 49, and so on in order up to '9'. That's where the 48 is coming from.
What you want to do is something more like this. First, you want to read the whole line, not just the first character; what if the user types "12"? Then you need parse the string "1" (or "12", which is two characters) to get the integer '1' or '12'.
And in fact, that's just what you did on this line:
print = Convert.ToInt32(Console.ReadLine());
So use that version every place that you've got print = Console.Read();
Second bug: You set print to some presumably small number, say the user types "4" so it's 4. Then you loop while it's greater than 10 -- but it's never greater than 10. You want to loop while it's greater than zero:
while (print > 0)
{
Console.WriteLine(cocaCola);
print -= 1;
}
You need to fix that in three places.
Update
Three places is more than you want to deal with. So here's another thing: You could simplify this code quite a bit by just setting a variable in the switch statement, and writing the loop only once (you could simplify it further in other ways, but let's take one step at a time):
Console.WriteLine("Would you like to print picture 1, 2, or 3?");
int print = 0;
string choice = "";
while (choice != "end")
{
choice = Console.ReadLine().Trim();
String thingToPrint = null;
switch (choice)
{
case "1":
thingToPrint = cocaCola;
break;
case "2":
thingToPrint = beam;
break;
case "3":
thingToPrint = liberty;
break;
}
if (thingToPrint != null)
{
Console.WriteLine("How many times would you like to print it");
print = Convert.ToInt32(Console.ReadLine());
while (print > 0)
{
Console.WriteLine(thingToPrint);
print -= 1;
}
}
else
{
Console.WriteLine("You chose poorly. Try again.");
}
Console.WriteLine("Choose again, or type \"end\" to exit");
}

C# - Cannot tag a random number with a statement

So i'm working on a revision tool that'll ask defined questions randomly using console command C#. I can create the random number but cannot seem to use the Switch function properly. Can anyone help?
// The random Object
Random Number = new Random();
while (true)
{
int Question = Number.Next(1);
Console.WriteLine("{0}", Question);
string Answer = Console.ReadLine();
if (Answer.ToLower() == "finished")
{
break;
}
if(Answer.Length == 0)
{
Console.WriteLine("Write Please");
continue;
}
switch (Question)
{
case 0:
{
Console.WriteLine("What is the nucleus of an atom made of");
if (Answer == "neutrons and protons")
{
Console.WriteLine("Well Done!");
}
if (Answer == "protons and neutrons")
{
Console.WriteLine("Well Done!");
}
Console.WriteLine("Try Again");
break;
}
}
}
}
}
}
Your code is quite strange; for example you are trying to read a response before you have even printed a question. However, your immediate question relating to the random number is simple.
You are using int Question = Number.Next(1);. According to MSDN:
Returns a non-negative random integer that is less than the specified maximum.
since you are storing the number as an int, and you have 1 as the specified maximum, you will always receive 0 from this assignment. I would assume that you have other case statements in your switch, and if you use the number of questions you have rather than 1, your switch will work. You will still have other issues with things printing in the wrong order, though....

How Can I Reduce Lines with Using Switch-Case Properly

I'm working on a Blackjack game project. I have a helper()method for helping user for their acts. For example:
dealer's up card is: 8
player's hand total is: 16
Player is not sure, should he hit or stay. helper() function takes action in here.
It's basically counts the number of good cards on deck (playerTotal + goodcard <= 21)
So I'm thinking about to do it in this way (pseudo code)
public void helper() {
remain = 21 - playerTotal;
if (remain == 1) {
for (int i = 0; i < deck.last(); i++) {
switch (deck[i]) {
case A: numOfGood += 1
default: numOfBad +=1
}
}
}
else if (remain == 2) {
for (....) {
switch (deck[i]) {
case A: numOfGood += 1
case 2: numOfGood += 1
default: numOfBad +=1
}
}
}
//goes like this
}
I need to build a switch-case and for loop for all cards(A,2,3,4,5,6,7,8,9,J,K,Q,K) but it seems like a huge mess. How can I reduce the number of lines by doing something different?
First write a GetValue method that can compute the (minimum) numeric value for a card. You can implement it with a switch or however else you want:
public static int GetValue(char card)
{
//...
}
Once you have that the implementation of your method becomes far shorter and simpler:
foreach(var card in deck)
if(GetValue(card) <= remain)
numOfGood++;
else
numOfBad++;
Also note that you could just count the number of good or bad cards, and use the total remaining cards to compute the other, if needed.
var oddsOfSuccessfulHit = deck.Count(card => GetValue(card) <= remain) /
(double) deck.Count;
You could use a HashSet, its probably a little more efficient to use a switch but if you want to save lines ...
var goodCards = new HashSet<char>(new[] { 'A', '2' });
then something like,
var numOfGood = deck.Count(card => goodCards.Contains(card));
var numOfBad = deck.Count - numOfGood;
Alternatively since the logic of card values cannot change, there is no need to code it - just store it as data.
struct CardEffect
{
public string CardGlyph;
public int MinValue;
public int MaxValue;
}
... load from XML file or some other location and load into ...
public Dictionary<string, CardEffect> cardValues;
Then use the logic Servy has suggested.

Beginner c# trouble

Im new to c# and Im having a little problem. I want to make an easy program to ask the user for a integer number between 1-50, and then to display on the console if its a odd number or not. So, what i tried is this:
Console.WriteLine("Skriv ut ett heltal: ");
int x = int.Parse(Console.ReadLine());
if (x == 1,3,5,7,9,11,13,15,17,19)
{
Console.WriteLine("The number is odd");
}
else
{
Console.WriteLine("The number is not odd");
}
Now i get an error at my if statements condition. How can i fix this?
C# does not allow you specify multiple values to check a variable against using a single if statement. You would need to check each value (1, 3, 5, etc) individually if you wanted to do it this way, and that would be a lot of redundant typing.
In this particular example, an easier way to check if something is odd or even is to check the remainder after dividing by 2, using the modulus operator %:
if (x % 2 == 1)
{
Console.WriteLine("The number is odd");
}
else
{
Console.WriteLine("The number is even");
}
However, if you really do need to check against a list, then the easy way is to use the Contains method on an array (an ICollection<T>, really). To make it nice and easy, you could even write an extension function that lets you check against a list in a syntactically pretty fashion:
public static class ExtensionFunctions
{
public static bool In<T>(this T v, params T[] vals)
{
return vals.Contains(v);
}
}
Then you could say:
if (x.In(1,3,5,7,9,11,13,15,17,19))
{
Console.WriteLine("The number is definitely odd and in range 1..19");
}
else
{
Console.WriteLine("The number is even, or is not in the range 1..19");
}
Voila! :)
if(x % 2 == 0)
{
// It's even
}
else
{
// It's odd
}
If you want to test whether x is a number in a particular list:
int[] list = new int[]{ 1,3,5,7,9,11,13,15,17,19};
if(list.Contains(x))
The common way to check to see if an integer is odd is to check if it divides evenly by 2:
if(x % 2 == 1)
x == 1,3,5,7,9,11,13,15,17,19 is not valid syntax for expressing multiple options. If you really want to do this then you can use a switch statement:
switch(x) {
case 1:
case 3:
case 5:
case 7:
case 9:
case 11:
case 13:
case 15:
case 17:
case 19:
// is odd
break;
default:
// is even
break;
}
The correct way would be to use the modulo operator % to determine if a number is exactly divisible by 2 or not, rather than trying every odd number, like so:
if( x % 2 == 0 ) {
// even number
} else {
// odd number
}
That's not valid C#. You can't test set inclusion like that. In any case, it's not practical to test for all the numbers in the world.
Why don't you just do this instead;
if (x &1 == 1) // mask the 1 bit
Bitwise operations are pretty quick so that code should be pretty fast.
Your if statement should be like this if you are having multiple conditions:
if any 1 of conditions is true:
if(x == 1 || x == 3 || x == 5)
{
//it is true
}
if all of the condition must be true:
if(x == 1 && y == 3 && z == 5)
{
//it is true
}
But if you are only looking for odd/even numbers. Use the % operator as the other answer says.
While, as others have pointed out, this is not the best way to solve this problem, the reason you're getting an error in this case is because you can't have multiple values like that in an if statement. You have to word it like this:
if (x == 1 || x == 3 || x == 5)
If you don't know, || is the symbol for 'or'
Try the following:
Console.WriteLine("Skriv ut ett heltal: ");
int x = int.Parse(Console.ReadLine());
Console.WriteLine(x % 2 == 1 ? "The number is odd" : "The number is not odd");
x % 2 == 1 does a modulus of 2 on the input (takes as many '2's off as possible until the number is between 0 and 2 - so 0 or 1 in this case)
One way to do that is:
if (x == 1 || 3 || 5){
Console.writeLine("oddetall");
}
or so it is possible to create an Array []
int[] odd = new int[3]; // how many odd to be tested
if(x=odd){
Console.WriteLine("Oddetall");
}

Categories

Resources