Reduce lines of code with switch statement - c#

I am teaching myself C# and one of the current chapters challenges asks me to prompt the user for a string, write back the string, count the number of characters, the instances of the letter 'e' and finally the instances of all vowels. It gave a hint to use switch but I couldn't figure out how to do it. I did get it to work by doing it manually, but I don't think that's the point. :) How could I use a switch statement to reduce the number of typed lines?
Console.WriteLine("Please type a sentence and hit enter: ");
string myString = Console.ReadLine();
int letterCount = myString.Split('e').Length - 1;
Console.Clear();
Console.WriteLine("Thank you. The sentence you entered was: \n\"{0}\"", myString);
Console.WriteLine("This sentence is {0} characters long.", myString.Length);
Console.WriteLine("It contains {0} instances of the letter \'e\'.", letterCount);
int vowelCount = 0;
int letterALower = myString.Split('a').Length - 1;
vowelCount += letterALower;
int letterELower = myString.Split('e').Length - 1;
vowelCount += letterELower;
int letterILower = myString.Split('i').Length - 1;
vowelCount += letterILower;
int letterOLower = myString.Split('o').Length - 1;
vowelCount += letterOLower;
int letterULower = myString.Split('u').Length - 1;
vowelCount += letterULower;
int letterAUpper = myString.Split('A').Length - 1;
vowelCount += letterAUpper;
int letterEUpper = myString.Split('E').Length - 1;
vowelCount += letterEUpper;
int letterIUpper = myString.Split('I').Length - 1;
vowelCount += letterIUpper;
int letterOUpper = myString.Split('O').Length - 1;
vowelCount += letterOUpper;
int letterUUpper = myString.Split('U').Length - 1;
vowelCount += letterUUpper;
Console.WriteLine("There are {0} vowels used.", vowelCount);
Console.ReadLine();

I know this isn't a good answer to the question, but I couldn't resist a one liner!
inputString.ToLower().Count(s=>"aeiou".Contains(s)); //count the vowels

Here's a simple solution:
string str = Console.ReadLine();
string low_str = str.ToLower();
Console.Clear();
Console.WriteLine("Thank you. The sentence you entered was: \n\"{0}\"", str);
Console.WriteLine("This sentence is {0} characters long.", str.Length);
int vowelCount = 0;
int eCount = 0;
for (int i = 0; i < low_str.Length; i++)
{
switch(low_str[i])
{
case 'e': eCount ++; vowelCount++; break;
case 'a': vowelCount++; break;
case 'o': vowelCount++; break;
case 'i': vowelCount++; break;
case 'u': vowelCount++; break;
case 'y': vowelCount++; break;
}
}
Console.WriteLine("It contains {0} instances of the letter \'e\'.", eCount);
Console.WriteLine("There are {0} vowels used.", vowelCount);
Console.ReadLine();
Notice that this could be done in an even fewer lines using this method (not the best way, but let's not go too deep into the framework details :) ):
int eCount = low_str.split(new char[]{'e'}) - 1;
int vowelCount = low_str.split(new char[]{'a','e','o','i','u','y'}) - 1;

Something like this (pseudo code, not actual C#)?
foreach (c in mySentence)
{
c = LowerCase(c);
switch (c) {
case 'a' :
case 'e' :
case 'i' :
case 'o' :
case 'u' :
nVowels ++;
break;
case ' ' :
case '\t' :
nBlanks++;
break;
default :
nChars++
break;
}
Here's a bit more info:
http://msdn.microsoft.com/en-us/library/06tc147t%28v=vs.80%29.aspx

I personally would do it with foreach and an array or vowels. This way it's easy to expand, like this:
Char[] vowels = {'e', 'a', 'o', 'i', 'u', 'y'};
string str = Console.ReadLine();
string low_str = str.ToLower();
Console.Clear();
Console.WriteLine("Thank you. The sentence you entered was: \n\"{0}\"", str);
Console.WriteLine("This sentence is {0} characters long.", str.Length);
int vowelCount = 0;
int eCount = 0;
foreach (char chara in low_str)
{
foreach (char vowel in vowels)
if (vowel == chara)
vowelCount++;
if (chara == 'e')
eCount++;
}
Console.WriteLine("It contains {0} instances of the letter \'e\'.", eCount);
Console.WriteLine("There are {0} vowels used.", vowelCount);
Console.ReadLine();

Related

for loop not executing/running correctly

Here's the code can anyone help?
using System;
namespace Mathhero
{
class MainClass
{
public static void Main(string[] args)
{
int i;
for (i = 0; i <= 10; i++)
{
Random numgen = new Random();
int num1 = numgen.Next(1, 11);
int num2 = numgen.Next(1, 11);
Console.WriteLine("What is " + num1 + " * " + num2 + " equal to ???");
int Answer = Convert.ToInt32(Console.ReadLine());
if (Answer == num1 * num2)
{
int ran = numgen.Next(1, 4);
switch (ran)
{
case 1:
Console.WriteLine("Good work!!");
break;
case 2:
Console.WriteLine("Nice!!!");
break;
default:
Console.WriteLine("Excellent!!");
break;
}
Console.WriteLine();
}
else
{
int ran = numgen.Next(1, 4);
switch (ran)
{
case 1:
Console.WriteLine("Wrong!!");
break;
case 2:
Console.WriteLine("Try hard!!!");
break;
default:
Console.WriteLine("DO homework!!");
break;
}
Console.WriteLine();
}
i=i+ 1;
}
Console.WriteLine("Test Ended!!!");
}
}
}
The for loop is exiting after 6 questions while it should after 10.
You are increasing your index within the for loop and thus shortening it's run.
else
{
int ran = numgen.Next(1, 4);
switch (ran)
{
case 1:
Console.WriteLine("Wrong!!");
break;
case 2:
Console.WriteLine("Try hard!!!");
break;
default:
Console.WriteLine("DO homework!!");
break;
}
Console.WriteLine();
}
i=i+ 1; //// <------- HERE
}
Your for loop already takes care of incrementing the index by itself.
Your for loop "header" increments i in the normal way:
for (i = 0; i <= 10; i++)
However, within the loop you also increment i, for no apparent reason:
i=i+ 1;
So you're incrementing i twice for each iteration of the loop. That makes it reach its end point earlier.
To execute 10 times, you should have:
for (i = 0; i < 10; i++)
(note the use of < rather than <=) and remove the i = i + 1; statement entirely.
I'd also recommend the general principle of declaring each variable in as small a scope as you can - in this case, in the for loop:
for (int i = 0; i < 10; i++)
That's more idiomatic and "tidy" IMO than declaring it before the loop.
the loop will run for 11 times as you are initializing i=0 and i<=10 so should check this...
Second i don't understand why are you doing i+1 at the end because loop is already incrementing so you should check this also..

Local variables - switch case

I am studying programming and I am very beginner (started 2 months ago).
I am doing a c# exercise for maths calculation. Our professor used a if ... else (embricated) loops to do the exercise. I wanted to use a switch case but I am struggling with the local variables.
I understand the issue: case 2 and 3 does not "know" the variables totalNumber and nbrSubAssy is as they come from case 1 and case 2, then they are detected as not assigned.
If I still want to use a switch case, what could I do to solve it?
using System;
namespace Denombrements
{
class Program
{
static long IntMultiplication(int startValue, int endValue)
{
long multiplication = 1;
for (int k = startValue; k <= endValue; k++)
multiplication *= k;
return multiplication;
}
static int UserSelection(String message)
{
int number = 0;
Console.Write(message);
try
{
number = int.Parse(Console.ReadLine());
Console.WriteLine();
}
catch
{
Console.WriteLine();
Console.WriteLine("Wrong input, enter an integer");
}
return number;
}
static void Main(string[] args)
{
char choice = '1';
while (choice != '0')
{
Console.WriteLine("Permutation ...................... 1");
Console.WriteLine("Arrangement ...................... 2");
Console.WriteLine("Combination ...................... 3");
Console.WriteLine("Quit ............................. 0");
Console.Write("Choice : ");
choice = Console.ReadKey().KeyChar;
Console.WriteLine();
switch(choice)
{
case '0':
Environment.Exit(0);
break;
case '1':
int totalNumber = UserSelection("Total number of elements to be taken into account");
long permutation = IntMultiplication(1, totalNumber);
Console.WriteLine(totalNumber + "! = " + permutation);
break;
case '2':
int nbrSubAssy = UserSelection("Total number of elements in the subassy to be taken into account");
long arrangement = IntMultiplication(totalNumber - nbrSubAssy + 1, totalNumber);
Console.WriteLine("A(" + totalNumber + "/" + nbrSubAssy + ") = " + arrangement);
break;
case '3':
long combination = arrangement / IntMultiplication(1, nbrSubAssy);
Console.WriteLine("C(" + totalNumber + "/" + nbrSubAssy + ") = " + combination);
break;
default:
Console.WriteLine("Wrong input");
break;
}
}
Console.ReadLine();
}
}
}
Declare your variable before While loop and it will keep the value of it for all the life of LOOP and you could access the old values
char choice = '1';
int nbrSubAssy = 0;
int totalNumber = 0;
long arrangement = 0;
while (choice != '0')
{
// code ...
switch (choice)
{
case '0':
Environment.Exit(0);
break;
case '1':
totalNumber = UserSelection("Total number of elements to be taken into account");
long permutation = IntMultiplication(1, totalNumber);
Console.WriteLine(totalNumber + "! = " + permutation);
break;
case '2':
nbrSubAssy = UserSelection("Total number of elements in the subassy to be taken into account");
arrangement = IntMultiplication(totalNumber - nbrSubAssy + 1, totalNumber);
Console.WriteLine("A(" + totalNumber + "/" + nbrSubAssy + ") = " + arrangement);
break;
case '3':
long combination = arrangement / IntMultiplication(1, nbrSubAssy);
Console.WriteLine("C(" + totalNumber + "/" + nbrSubAssy + ") = " + combination);
break;
default:
Console.WriteLine("Wrong input");
break;
}
}
or in my opinion the better solution you could ask for the value in every case you need them

Control Cannot Fall Through From One Case Label To Another Even With Break

This is some part of the code.
I am getting the error "Control cannot fall through from one case label to another in case 3".
In spite of using the break statement, it is not getting detected. What is the right way to do it?
Update: Error is in case 3. Don't bother to waste your time on other cases.
switch (output)
{
case 1:
int num, reverse = 0;
Console.WriteLine("Enter a Number : ");
num = int.Parse(Console.ReadLine());
while (num != 0)
{
reverse = reverse * 10;
reverse = reverse + num % 10;
num = num / 10;
}
Console.WriteLine("Reverse of Number is : "+reverse);
Console.ReadLine();
break;
case 2:
int number, sum = 0, r,square;
Console.WriteLine("Enter a Number : ");
number = int.Parse(Console.ReadLine());
while (number != 0)
{
r = number % 10;
number = number / 10;
square = r * r;
sum = sum + square;
}
Console.WriteLine("Sum of square of Digits of the Number : "+sum);
Console.ReadLine();
break;
case 3:
Console.WriteLine("Enter 1 for AND 2 for OR and 3 for XOR Operation");
int answer = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Your 2 inputs are?");
int inp1= Convert.ToInt32(Console.ReadLine());
int inp2= Convert.ToInt32(Console.ReadLine());
switch (answer)
{
case 1:
int input3 = inp1 * inp2;
System.Console.WriteLine("Output is" + input3);
Console.ReadLine();
break;
case 2:
int input4 = inp1 + inp2;
System.Console.WriteLine("Output is" + input4);
Console.ReadLine();
break;
case 3:
if (inp1 == inp2)
{
System.Console.WriteLine("OUTPUT IS 0");
Console.ReadLine();
}
else
{
System.Console.WriteLine("Output is 1");
Console.ReadLine();
}
break;
Your problem is that you only break out of the inner case and not the outer, so you're getting a fall through issue.
case 3 ...
case 3:
if (inp1 == inp2)
{
System.Console.WriteLine("OUTPUT IS 0");
Console.ReadLine();
}
else
{
System.Console.WriteLine("Output is 1");
Console.ReadLine();
}
break;
break; //break the outer case3
Add a goto case X in place of the break for where you want the fall though to occur.
... never mind. you need an expression block on the first case 3.
case 3
{
/// your other switch here
break;
}
By not using scoping blocks you overlooked the outer case statement. It needs break as well as the inner statement.

How can I [ go to ] using switch

How can I edit this code, if the user enter wrong char? Like " g " or " H " or anything else, repeat this step again, and don't go to the next step [ I mean ] if I loop for 10 loops, if I enter wrong char it will loop for 9 just
char grade; // one grade
int aCount = 0, // number of As
bCount = 0, // number of Bs
cCount = 0, // number of Cs
dCount = 0, // number of Ds
fCount = 0; // number of Fs
for ( int i = 1; i <= 10; i++ )
{
Console.Write( "Enter a letter grade: " );
grade = Char.Parse( Console.ReadLine() );
switch ( grade )
{
case 'A': // grade is uppercase A
case 'a': // or lowercase a
++aCount;
break;
case 'B': // grade is uppercase B
case 'b': // or lowercase b
++bCount;
break;
case 'C': // grade is uppercase C
case 'c': // or lowercase c
++cCount;
break;
case 'D': // grade is uppercase D
case 'd': // or lowercase d
++dCount;
break;
case 'F': // grade is uppercase F
case 'f': // or lowercase f
++fCount;
break;
default: // processes all other characters
Console.WriteLine(
"Incorrect letter grade entered." +
"\nEnter a new grade" );
break;
} // end switch
} // end for
Console.WriteLine(
"\nTotals for each letter grade are:\nA: {0}" +
"\nB: {1}\nC: {2}\nD: {3}\nF: {4}", aCount, bCount,
cCount, dCount, fCount );
You could make this a lot more dynamic and easier to read. Plus using the dictionary makes it a lot easier to add another grade without modifying so much code.
However, you can solve your problem by keeping track of an acceptedGradeCount for every grade you accept and running the loop 10 times using that to compare against. Which is what you should do in your code.
You can also use char.ToLower to convert a character to lower case so that you don't need to compare against upper as well.
//Dictionary of grades with default counts of 0 per grade
var dict = new Dictionary<char, int>()
{
{'a', 0},
{'b', 0},
{'c', 0},
{'d', 0},
{'f', 0},
};
var acceptedGradeCount = 0;
//While accepted grade count is less than 10
while (acceptedGradeCount < 10)
{
Console.WriteLine("Enter a letter grade: ");
//Read in the character and convert it to lower case
var input = char.ToLower(Convert.ToChar(Console.ReadLine()));
//Determine if the character is a valid grade by seeing if it exists in the dictionary
if (dict.ContainsKey(input))
{
//Add 1 to the dictionary count value for that grade
dict[input]++;
acceptedGradeCount++;
}
else
{
Console.WriteLine("Incorrect letter grade entered. {0}Enter a new grade", Environment.NewLine);
}
}
//Get results string
var builder = new StringBuilder("Totals for each letter grade are:");
foreach (KeyValuePair<char, int> keyValuePair in dict)
{
builder.Append(string.Format("{0}: {1} ", keyValuePair.Key, keyValuePair.Value));
}
//Print Results
Console.WriteLine(builder.ToString());
Console.ReadLine();
To stay with your current code, you could add acceptedGradeCount and increment it in each accepted grade. Use a while loop instead of a for also.
char grade; // one grade
int aCount = 0, // number of As
bCount = 0, // number of Bs
cCount = 0, // number of Cs
dCount = 0, // number of Ds
fCount = 0; // number of Fs
var acceptedGradeCount = 0;
while(acceptedGradeCount < 10)
{
Console.Write("Enter a letter grade: ");
grade = char.ToLower(Char.Parse(Console.ReadLine()));
switch (grade)
{
case 'a': // or lowercase a
++aCount;
acceptedGradeCount++;
break;
case 'b': // or lowercase b
++bCount;
acceptedGradeCount++;
break;
case 'c': // or lowercase c
++cCount;
acceptedGradeCount++;
break;
case 'd': // or lowercase d
++dCount;
acceptedGradeCount++;
break;
case 'f': // or lowercase f
++fCount;
acceptedGradeCount++;
break;
default: // processes all other characters
Console.WriteLine(
"Incorrect letter grade entered." +
"\nEnter a new grade");
break;
} // end switch
} // end for
Console.WriteLine(
"\nTotals for each letter grade are:\nA: {0}" +
"\nB: {1}\nC: {2}\nD: {3}\nF: {4}", aCount, bCount,
cCount, dCount, fCount);
Didn't read the question before answering previously. Appologies. Check this
static void Main(string[] args)
{
char grade; // one grade
int aCount = 0, // number of As
bCount = 0, // number of Bs
cCount = 0, // number of Cs
dCount = 0, // number of Ds
fCount = 0; // number of Fs
AskForChar(ref aCount, ref bCount, ref cCount, ref dCount, ref fCount); // end switch
// end for
Console.WriteLine(
"\nTotals for each letter grade are:\nA: {0}" +
"\nB: {1}\nC: {2}\nD: {3}\nF: {4}", aCount, bCount,
cCount, dCount, fCount);
Console.ReadLine();
}
private static void AskForChar(ref int aCount, ref int bCount, ref int cCount, ref int dCount, ref int fCount)
{
for (int i = 1; i <= 10; i++)
{
char grade;
Console.Write("Enter a letter grade: ");
grade = Char.Parse(Console.ReadLine());
switch (grade)
{
case 'A': // grade is uppercase A
case 'a': // or lowercase a
++aCount;
break;
case 'B': // grade is uppercase B
case 'b': // or lowercase b
++bCount;
break;
case 'C': // grade is uppercase C
case 'c': // or lowercase c
++cCount;
break;
case 'D': // grade is uppercase D
case 'd': // or lowercase d
++dCount;
break;
case 'F': // grade is uppercase F
case 'f': // or lowercase f
++fCount;
break;
default: // processes all other characters
Console.WriteLine(
"Incorrect letter grade entered." +
"\nEnter a new grade");
return;
break;
}
}
}

Evaluate escaped string

I have some strings in a file that are already escaped. So the content of the file looks like this:
Hello\nWorld. This is\tGreat.
When I read the file, I get \n as two different characters instead of one.
How can I convert an escaped string to a non-escaped one?
based on #deAtog 's code, i made some minor additions
support \U00000000 format chars
simplify the hex conversions somewhat
string UnEscape(string s)
{
StringBuilder sb = new StringBuilder();
Regex r = new Regex("\\\\[abfnrtv?\"'\\\\]|\\\\[0-3]?[0-7]{1,2}|\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}|.");
MatchCollection mc = r.Matches(s, 0);
foreach (Match m in mc)
{
if (m.Length == 1)
{
sb.Append(m.Value);
}
else
{
if (m.Value[1] >= '0' && m.Value[1] <= '7')
{
int i = Convert.ToInt32(m.Value.Substring(1), 8);
sb.Append((char)i);
}
else if (m.Value[1] == 'u')
{
int i = Convert.ToInt32(m.Value.Substring(2), 16);
sb.Append((char)i);
}
else if (m.Value[1] == 'U')
{
int i = Convert.ToInt32(m.Value.Substring(2), 16);
sb.Append(char.ConvertFromUtf32(i));
}
else
{
switch (m.Value[1])
{
case 'a':
sb.Append('\a');
break;
case 'b':
sb.Append('\b');
break;
case 'f':
sb.Append('\f');
break;
case 'n':
sb.Append('\n');
break;
case 'r':
sb.Append('\r');
break;
case 't':
sb.Append('\t');
break;
case 'v':
sb.Append('\v');
break;
default:
sb.Append(m.Value[1]);
break;
}
}
}
}
return sb.ToString();
}
You can try using System.Text.RegularExpressions.Regex.Unescape.
There's also an entry on the MSDN forums.
See also How can I Unescape and Reescape strings in .net? .
Like you I was unable to find a decent solution to this problem. While you can certainly use String.Replace, the performance and speed of this solution is terrible. Furthermore, it's hard to support octal and Unicode escape sequences via this method. A much better alternative is to use a simple RegEx parser. Here's a method that will properly un-escape any string given. It supports standard escape sequences, octal escape sequences, and unicode escape sequences.
string UnEscape(string s) {
StringBuilder sb = new StringBuilder();
Regex r = new Regex("\\\\[abfnrtv?\"'\\\\]|\\\\[0-3]?[0-7]{1,2}|\\\\u[0-9a-fA-F]{4}|.");
MatchCollection mc = r.Matches(s, 0);
foreach (Match m in mc) {
if (m.Length == 1) {
sb.Append(m.Value);
} else {
if (m.Value[1] >= '0' && m.Value[1] <= '7') {
int i = 0;
for (int j = 1; j < m.Length; j++) {
i *= 8;
i += m.Value[j] - '0';
}
sb.Append((char)i);
} else if (m.Value[1] == 'u') {
int i = 0;
for (int j = 2; j < m.Length; j++) {
i *= 16;
if (m.Value[j] >= '0' && m.Value[j] <= '9') {
i += m.Value[j] - '0';
} else if (m.Value[j] >= 'A' && m.Value[j] <= 'F') {
i += m.Value[j] - 'A' + 10;
} else if (m.Value[j] >= 'a' && m.Value[j] <= 'f') {
i += m.Value[j] - 'a' + 10;
}
}
sb.Append((char)i);
} else {
switch (m.Value[1]) {
case 'a':
sb.Append('\a');
break;
case 'b':
sb.Append('\b');
break;
case 'f':
sb.Append('\f');
break;
case 'n':
sb.Append('\n');
break;
case 'r':
sb.Append('\r');
break;
case 't':
sb.Append('\t');
break;
case 'v':
sb.Append('\v');
break;
default:
sb.Append(m.Value[1]);
break;
}
}
}
}
return sb.ToString();
}
you could do something like:
string str = str.Replace(#"\n","\n");
update:
Obviously this is a workaround as the scenario is "un natural" by itself. The Regex.Unescape solution is unapplicable here as it is intended to use for unescaping regex control characters, and not new lines etc.
In order to support other relevant characters one can write a replacing function like this one:
public string ReEscapeControlCharacters(string str) {
return str.Replace(#"\n","\n").Replace(#"\r","\r").Replace(#"\t","\t");
}
Try this:
String replaced = startstring.Replace(System.Environment.NewLine, desirevalue);
This have to be valid only for "\n".

Categories

Resources