-
December 1st, 2011, 03:43 PM
#1
Please don't cringe
Now, I know, you didn't think neanderthals still existed, but you may be persuaded otherwise after reading this. So, I need to create a program that will take a letter and give the corresponding number from a phone keypad. For example, I enter a b or c, and it gives me 2...and so on. I figured I could use a switch statement. However, I soon realized the whole (can't convert string to bool), so my question is...how do I take the string input and match it to each of the cases? You don;t have to tell me how to do it, just give a hint or two. As usual, you're all very helpful and I appreciate any response. (I realize there is probably a lot of other things wrong with the code, but I'll take it one step at a time).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string option;
while (option)
{
DisplayMenu();
option = (Console.ReadLine());
switch (option)
{
case "a,b,c":
Console.WriteLine("2");
break;
case "d,e,f":
Console.WriteLine("3");
break;
case "g,h,i":
Console.WriteLine("4");
break;
case "j,k,l":
Console.WriteLine("5");
break;
case "m,n,o":
Console.WriteLine("6");
break;
case "p,q,r,s":
Console.WriteLine("7");
break;
case "t,u,v":
Console.WriteLine("8");
break;
case "w,x,y,z":
Console.WriteLine("9");
break;
}
}
}
static void DisplayMenu()
{
Console.WriteLine("Enter a letter:");
}
}
}
-
December 1st, 2011, 03:52 PM
#2
Re: Please don't cringe
case "a":
case "b":
case "c":
Console.WriteLine("1");
break;
-
December 1st, 2011, 04:10 PM
#3
Re: Please don't cringe
Originally Posted by Silent Sojourner
case "a":
case "b":
case "c":
Console.WriteLine("1");
break;
Thank you! I've made those changes, now I just gotta figure out how to take the user input and match it to each case...
-
December 1st, 2011, 07:28 PM
#4
Re: Please don't cringe
Maybe I should convert the string to an int?
-
December 1st, 2011, 09:02 PM
#5
Re: Please don't cringe
My preference is to do data encoding in variables to separate data entry from logical execution.
I'd use a Dictionary<string, int> to perform this conversion like this:
Code:
static Dictionary<string, int> numberMap;
public static void Main(string[] args)
{
//EDIT: ----------->WARNING!!!!!<---------------
//EDIT: THERE IS AN ERROR IN THIS SUBROUTINE; SEE MY LATER POST FOR CORRECTION
for(int i = 0; i < numberMap; i++)
{
//Initialize the dictionary
numberMap = new Dictionary<string, int>() {
{ "a", 2 },
{ "a", 2 },
{ "c", 2 },
{ "d", 2 },
{ "e", 2 },
{ "f", 2 },
//... and so sorth
{ "z", 9 } };
}
}
public static mapToNumber(string letter)
{
return numberMap[letter];
}
This has the advantage of returning in O(1) time [instead of the potentially O(n) of the switch statement; although in some cases switch's may be optimized to O(1) by the compiler by generating a jump table [see link]].
Last edited by BioPhysEngr; December 2nd, 2011 at 03:10 AM.
Reason: write a note that there is an error in the subroutine
Best Regards,
BioPhysEngr
http://blog.biophysengr.net
--
All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.
-
December 2nd, 2011, 02:15 AM
#6
Re: Please don't cringe
Hmmm like your code BioPhysEngr I always seem to learn something new from all your post
I am curious on why you have a for loop when creating the dictionary?
I also wanted to ask would my approach to the problem have been different in a bad way or just in a design way?
Code:
string userInput = "";
string[] letterNumber = new string[]{" ", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
Console.Write("Please enter a letter: ");
userInput = Console.ReadLine();
for (int i = 0; i < letterNumber.Length; i++)
{
if (letterNumber[i].Contains(userInput))
{
Console.WriteLine(i);
break;
}
}
Console.Write("\nPress any key to continue...");
Console.ReadKey();
I'm gonna take a guess and say that code could probably lag behind in a larger scale operation vs the dictionary? I am gonna do some research on the dictionary as in my previous self taught attempts I never really looked at it but it does seem like a helpful function.
-
December 2nd, 2011, 03:09 AM
#7
Re: Please don't cringe
Originally Posted by Ubiquitous
I am curious on why you have a for loop when creating the dictionary?
D'oh! There's no reason at all; I must have gotten distracted when I was replying. Actually, the loop doesn't even make syntactical sense (i < numberMap makes no sense). Good catch! (EDIT: Actually there were a few more minor syntax errors in the Main method...! >__< Fixed now.)
The method should read:
Code:
public static void Main(string[] args)
{
//Initialize the dictionary
numberMap = new Dictionary<string, int>() {
{ "a", 2 },
{ "b", 2 },
{ "c", 2 },
{ "d", 3 },
{ "e", 3 },
{ "f", 3 },
//... and so forth
{ "z", 9 } };
}
The primary advantage of Dictionary<,> (MSDN link) is that it allows for O(1) average time for search, insertion and deletion (constant time no matter how many elements are in the dictionary). Dictionary<,> is actually just the C# generics way of defining a hash table (link on Wikipedia), which might be a more familiar concept.
I think I would prefer the switch method or the Dictionary<,> method to your solution (though there is nothing incorrect about your solution). Using both switch or Dictionary<,>, it will probably require O(1) time to run the method [as I mentioned, switch can be optimized to O(1) automatically by the compiler in some cases]). The solution you propose requires scanning through the array until you find the match, which requires O(n) time where n is the number of element in the array. For small values of n, your way might be faster for some overhead reasons, but for large values of n the Dictionary method will almost certainly yield superior performance.
Last edited by BioPhysEngr; December 2nd, 2011 at 03:12 AM.
Best Regards,
BioPhysEngr
http://blog.biophysengr.net
--
All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.
-
December 2nd, 2011, 03:24 AM
#8
Re: Please don't cringe
Originally Posted by JohnYossarian
I've made those changes, now I just gotta figure out how to take the user input and match it to each case...
Sorry, I missed this originally. To query the user for input on the console, check for valid input and convert the letter to a number do:
Code:
public static int requestInputAndConvertToNumber()
{
string input = null;
while(true)
{
//Prompt user
Console.Write("Enter number: ");
//Get input from the user
input = Console.ReadLine(); //Also ReadKey might be useful
//Check to see if this input is in the dictionary; if so store the numerical value
// in result
int result = 0;
bool inDictionary = numberMap.TryGetValue(input, out result);
if( !inDictionary )
{
//Complain
Console.WriteLine("Hey! That number wasn't valid!");
continue; //Restart the loop to try again
}
//Otherwise return the result (the corresponding integer)
return result;
}
}
Hopefully no bugs this time. :-)
Does that make sense? If not, push back!
Best Regards,
BioPhysEngr
http://blog.biophysengr.net
--
All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.
-
December 2nd, 2011, 11:26 AM
#9
Re: Please don't cringe
BPE, I share your aversion to goto, but I have a similar aversion to 'continue'. I have never used it, since it is easily avoided.
Assuming your code is correct (I haven't tested it), I have rewritten the function to avoid the 'continue'.
Code:
public static int requestInputAndConvertToNumber()
{
string input = null;
int result = 0;
bool LoopFinished = false;
while(!LoopFinished)
{
//Prompt user
Console.Write("Enter number: ");
//Get input from the user
input = Console.ReadLine(); //Also ReadKey might be useful
//Check to see if this input is in the dictionary; if so store the numerical value
// in result
bool inDictionary = numberMap.TryGetValue(input, out result);
if( !inDictionary )
{
//Complain
Console.WriteLine("Hey! That number wasn't valid!");
}
else
{
LoopFinished = true;
}
//Otherwise return the result (the corresponding integer)
}
return result;
}
Developing using:
.NET3.5 / VS 2010
-
December 2nd, 2011, 07:54 PM
#10
Re: Please don't cringe
BPE, I share your aversion to goto, but I have a similar aversion to 'continue', since it is easily avoided.
I think, perhaps, that you ought re-consider your aversion. The objection to goto isn't that it's unnecessary (though it is), but rather that it leads to unmaintainable code. When a programmer uses goto, understanding what happens next in the program requires the programmer already know (or look up) where the label is. Humans are bad at that. Therefore, use of goto leads to the production of hard-to-read and hard-to-maintain code.
By contrast, the flow control statements break and continue have fixed interpretations. They always means "stop processing this loop" and "stop processing, for this iteration". They simply mark the end of an iteration (or a loop). For this reason, they are primary tools used in structured programming.
While you are correct that you can avoid it by using if { ... } else { ... }, I would argue that my construct is more readable because the if { ... } else { ... } clause if unnecessarily verbose. When you should use if { ... } else { ... } is when you are processing some data and need to differentially process based on some condition and then keep processing it.
Best Regards,
BioPhysEngr
http://blog.biophysengr.net
--
All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.
-
December 2nd, 2011, 09:02 PM
#11
Re: Please don't cringe
BPE, I have programmed using coding standards that strictly forbade the use of goto, continue and multiple returns from a function. I didn't write the standards, but I agreed with them and followed them. I remember going to a convention where a debugger company was demonstrating their debugger they had for sale. Which example did they use to demonstrate the debugger? -A block of code that contained a 'continue' statement. I thought to myself, if they had just not used the 'continue' statement, they wouldn't have had to use a debugger. Also, a lot of coders today violate the prohibition of multiple returns from functions. This practice makes code more difficult to maintain. The rules were made for a reason - to prevent people from writing code that is difficult to maintain.
Developing using:
.NET3.5 / VS 2010
-
December 2nd, 2011, 11:30 PM
#12
Re: Please don't cringe
I guess I am merely at variance with those who forbid continue and multiple returns then. The rationale is not clearly laid out beyond appeal to authority. The interpretation of continue and return -- "no further need to process this; move on" -- have fixed interpretations (unlike goto) that can simply code and make functions more communicative. I don't see any reason to recommend against their use.
As a specific example, however, how would you code a recursive factorial function:
Code:
public static int factorial(int n)
{
//Base case
if( n < 1 )
return 1;
return n*factorial(n-1);
}
It's not clear to me that saving the return value to a result variable using if { ... } else { ... } and then returning result would do anything other than add verbosity.
Or how about a parsing example wherein you want to ignore blank lines:
Code:
StreamReader r = new StreamReader(path);
while( !r.EndOfStream)
{
string line = r.ReadLine();
//Skip empty lines
if( string.IsNullOrWhitespace(line) )
continue;
//...Downstream processing here...
}
You'd actually wrap the entire interior loop indented under else? To my mind, the ugliness and verbosity caused by not using continue appropriately is a heavy cost to readability.
Also: Do others have any useful comments? If my viewpoint is a minority one, I would be glad to hear the rationale for why it is flawed.
Last edited by BioPhysEngr; December 2nd, 2011 at 11:33 PM.
Best Regards,
BioPhysEngr
http://blog.biophysengr.net
--
All advice is offered in good faith only. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.
-
December 3rd, 2011, 10:52 AM
#13
Re: Please don't cringe
No, you are not in the minority. If you make it a popularity contest, of course you will win.
People like to take the easy way out and don't care about who has to maintain their code later.
If you had to maintain code other people had hacked together, you would wish they had followed a coding standard.
Developing using:
.NET3.5 / VS 2010
-
December 3rd, 2011, 07:22 PM
#14
Re: Please don't cringe
Coders should be flexible enough to code to whatever standards are required of them: do as youre told, earn your money, with it do as you want
Here are no wrongs and rights with goto/continue/break/return - just use them as and when and as not asked. Oh and stop arguing about it; there are better things to do with your life
-
December 4th, 2011, 10:30 PM
#15
Re: Please don't cringe
Originally Posted by BioPhysEngr
Sorry, I missed this originally. To query the user for input on the console, check for valid input and convert the letter to a number do:
Code:
public static int requestInputAndConvertToNumber()
{
string input = null;
while(true)
{
//Prompt user
Console.Write("Enter number: ");
//Get input from the user
input = Console.ReadLine(); //Also ReadKey might be useful
//Check to see if this input is in the dictionary; if so store the numerical value
// in result
int result = 0;
bool inDictionary = numberMap.TryGetValue(input, out result);
if( !inDictionary )
{
//Complain
Console.WriteLine("Hey! That number wasn't valid!");
continue; //Restart the loop to try again
}
//Otherwise return the result (the corresponding integer)
return result;
}
}
Hopefully no bugs this time. :-)
Does that make sense? If not, push back!
The posts so far have been invaluable, thank you. I am still very much a beginner and have turned to this forum among other places to learn. Thus, some of the terms/concepts I am still trying to grasp. I have tried to interpret what you've posted and came up with this:
Code:
namespace keyPad
{
class Program
{
public static void Main(string[] args)
{
//Initialize the dictionary
numberMap = new Dictionary<string, int>()
{
{ "a", 2 },
{ "b", 2 },
{ "c", 2 },
{ "d", 3 },
{ "e", 3 },
{ "f", 3 },
{ "g", 4 },
{ "h", 4 },
{ "i", 4 },
{ "j", 5 },
{ "k", 5 },
{ "l", 5 },
{ "m", 6 },
{ "n", 6 },
{ "o", 6 },
{ "p", 7 },
{ "q", 7 },
{ "r", 7 },
{ "s", 7 },
{ "t", 8 },
{ "u", 8 },
{ "v", 8 },
{ "w", 2 },
{ "x", 2 },
{ "y", 2 },
{ "z", 9 }};
}
public static int requestInputAndConvertToNumber()
{
string input = null;
while (true)
{
//Prompt user
Console.Write("Enter number: ");
//Get input from the user
input = Console.ReadLine(); //Also ReadKey might be useful
//Check to see if this input is in the dictionary; if so store the numerical value
// in result
int result = 0;
bool inDictionary = numberMap.TryGetValue(input, out result);
if (!inDictionary)
{
//Complain
Console.WriteLine("Hey! That number wasn't valid!");
continue; //Restart the loop to try again
}
//Otherwise return the result (the corresponding integer)
return result;
}
}
}
}
Is this interpretation correct? Don't cringe when I ask this: numberMap is listed as not existing in this context? I know it's something blatant that should be obvious.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|