patterncsharpMajor
Converting the weight of a potato into a letter grade
Viewed 0 times
theintogradeweightpotatoletterconverting
Problem
I've just started learning C# using Rob Miles' C# Programming Yellow Book and some related lab exercises from his website. I did one of them and produced a solution that works. In Miles' book, he says that nesting if and else brackets is clumsy and introduces the switch. But switch apparently doesn't work with Boolean operators, e.g. case x < 201, so I can't use it. I could just have independent, non-nested if statements, though their conditions would have to be longer. Any other ideas?
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Program
{
static int GetIntNumber(int min, int max, string prompt, string inputPrompt)
{
int number;
Console.Write(prompt);
do //loops as long as input is not between min and max
{
while (!int.TryParse(Console.ReadLine(), out number)) //loops as long as the input is not an integer
{
Console.Write("\nYou must enter an integer number!: ");
}
if (number max) Console.Write(inputPrompt); // max);
return number;
}
static void printGrade(string grade)
{
Console.WriteLine("\nYour potato is grade " + grade);
}
static void Main()
{
do
{
int weight = GetIntNumber(0, 1500, "\nEnter the weight of the potato in grams: ", "\nEnter an integer between 0 and 1500: ");
if (weight < 201)
{
printGrade("X");
}
else
{
if (weight < 401)
{
printGrade("A");
}
else
{
if (weight < 801)
{
printGrade("B");
}
else
printGrade("Z");
}
}
Console.WriteLine("\nPress any key to c
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Program
{
static int GetIntNumber(int min, int max, string prompt, string inputPrompt)
{
int number;
Console.Write(prompt);
do //loops as long as input is not between min and max
{
while (!int.TryParse(Console.ReadLine(), out number)) //loops as long as the input is not an integer
{
Console.Write("\nYou must enter an integer number!: ");
}
if (number max) Console.Write(inputPrompt); // max);
return number;
}
static void printGrade(string grade)
{
Console.WriteLine("\nYour potato is grade " + grade);
}
static void Main()
{
do
{
int weight = GetIntNumber(0, 1500, "\nEnter the weight of the potato in grams: ", "\nEnter an integer between 0 and 1500: ");
if (weight < 201)
{
printGrade("X");
}
else
{
if (weight < 401)
{
printGrade("A");
}
else
{
if (weight < 801)
{
printGrade("B");
}
else
printGrade("Z");
}
}
Console.WriteLine("\nPress any key to c
Solution
You are very much correct that
Since you tagged your question beginner I'll be gentle with the explanation.
The first thing we'll do is make a
So, this means if the value is
Next, we'll simply one-line this entire operation in LINQ:
What's happening here? LINQ is Language Integrated Query, if you've ever worked with SQL you might recognize the Query bit, essentially, LINQ allows you to build code which looks and act's like a query against an
So if we take this step-by-step, we can start with our dictionary as follows:
The
Next, we do a
So, now we have the
And viola, we have our value. :)
We can combine this together and get:
So, the final thing we have to do is combine it with your original programme:
The next best thing would be to extract the LINQ logic into a new method:
Then our
Now if you need to add a new grade, for whatever reason, it's trivial.
Also: if you're not using C#6.0, you will have to replace
Good work so far, hopefully you continue improving and learn more regarding C# and the paradigms it holds. :)
The answer by t3chb0t is also very good, I recommend reading it thoroughly as well (especially the bit about method overloading).
switch statements cannot take boolean operators like that: switch statements are used to build jump tables, and can only use constants to do so. However, you can easily come up with a fairly robust solution to your problem using a Dictionary and some LINQ.Since you tagged your question beginner I'll be gentle with the explanation.
The first thing we'll do is make a
Dictionary which represents the lowest value associated with each grade.var gradeMap = new Dictionary
{
[0] = "X",
[201] = "A",
[401] = "B",
[801] = "Z",
};So, this means if the value is
>= 801, then it's Z, and so on.Next, we'll simply one-line this entire operation in LINQ:
gradeMap.OrderByDescending(x => x.Key).FirstOrDefault(x => x.Key <= testWeight).ValueWhat's happening here? LINQ is Language Integrated Query, if you've ever worked with SQL you might recognize the Query bit, essentially, LINQ allows you to build code which looks and act's like a query against an
IEnumerable object (which Dictionary is).So if we take this step-by-step, we can start with our dictionary as follows:
0: X
201: A
401: B
801: ZThe
gradeMap.OrderByDescending(x => x.Key) bit will first take the entire gradeMap dictionary, and order it by the key value in highest-to-lowest order:801: Z
401: B
201: A
0: XNext, we do a
FirstOrDefault(x => x.Key <= testWeight), which will loop through all the elements (in the backwards order we have them) that are in the dictionary, and find the first one that matches our expression (x.Key <= testWeight). The x.Key is the reference to the key of the dictionary (our int values):801: Z (Skipped)
401: B (Skipped)
201: A (Matched)So, now we have the
201: A item from the dictionary, the last part is to get .Value on it which returns the string portion of it:AAnd viola, we have our value. :)
We can combine this together and get:
var testWeight = 205;
var grade = gradeMap.OrderByDescending(x => x.Key).FirstOrDefault(x => x.Key <= testWeight).Value;So, the final thing we have to do is combine it with your original programme:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Program
{
static int GetIntNumber(int min, int max, string prompt, string inputPrompt)
{
int number;
Console.Write(prompt);
do //loops as long as input is not between min and max
{
while (!int.TryParse(Console.ReadLine(), out number)) //loops as long as the input is not an integer
{
Console.Write("\nYou must enter an integer number!: ");
}
if (number max) Console.Write(inputPrompt); // max);
return number;
}
static void printGrade(string grade)
{
Console.WriteLine("\nYour potato is grade " + grade);
}
static void Main()
{
do
{
var gradeMap = new Dictionary
{
[0] = "X",
[201] = "A",
[401] = "B",
[801] = "Z",
};
int weight = GetIntNumber(0, 1500, "\nEnter the weight of the potato in grams: ", "\nEnter an integer between 0 and 1500: ");
printGrade(gradeMap.OrderByDescending(x => x.Key).FirstOrDefault(x => x.Key <= weight).Value);
Console.WriteLine("\nPress any key to check the grade of another potato.");
} while (Console.ReadKey(true).Key != ConsoleKey.Escape );
Console.Read();
}
}The next best thing would be to extract the LINQ logic into a new method:
public string GetGrade(int weight)
{
var gradeMap = new Dictionary
{
[0] = "X",
[201] = "A",
[401] = "B",
[801] = "Z",
};
return gradeMap.OrderByDescending(x => x.Key).FirstOrDefault(x => x.Key <= weight).Value;
}Then our
Main method becomes:static void Main()
{
do
{
int weight = GetIntNumber(0, 1500, "\nEnter the weight of the potato in grams: ", "\nEnter an integer between 0 and 1500: ");
printGrade(GetGrade(weight));
Console.WriteLine("\nPress any key to check the grade of another potato.");
} while (Console.ReadKey(true).Key != ConsoleKey.Escape );
Console.Read();
}Now if you need to add a new grade, for whatever reason, it's trivial.
Also: if you're not using C#6.0, you will have to replace
var gradeMap with the following:var gradeMap = new Dictionary
{
{0, "X"},
{201, "A"},
{401, "B"},
{801, "Z"}
};Good work so far, hopefully you continue improving and learn more regarding C# and the paradigms it holds. :)
The answer by t3chb0t is also very good, I recommend reading it thoroughly as well (especially the bit about method overloading).
Code Snippets
var gradeMap = new Dictionary<int, string>
{
[0] = "X",
[201] = "A",
[401] = "B",
[801] = "Z",
};gradeMap.OrderByDescending(x => x.Key).FirstOrDefault(x => x.Key <= testWeight).Value0: X
201: A
401: B
801: Z801: Z
401: B
201: A
0: X801: Z (Skipped)
401: B (Skipped)
201: A (Matched)Context
StackExchange Code Review Q#146307, answer score: 26
Revisions (0)
No revisions yet.