Question: Take an input string and output the "encoded" string by using the following rules:
[1] vowels are replaced with number: a->1, e->2, etc [2] consonants are replaced with previous letter b->a, c->b, etc [3] y goes to space [4] space goes to y [5] numbers are reversed [6] other characters remain unchanged(punctuation, etc.) [7] all output should be lower case E.g.: Hello World! => g2kk4yv4qkc!
My Solution:
/// pre processed conversions for letters
private static Dictionary<char, char> Convert;
public static string encode(string stringToEncode) {
// approach: pre process a mapping (dictionary) for letter conversions
// use a Dict for fastest look ups. The first run, will take a little
// extra time, subsequent usage will perform even better
if (Convert == null || Convert.Count == 0) BuildConversionMappings();
// our return val (efficient Appends)
StringBuilder sb = new StringBuilder();
// used for reversing the numbers
Stack<char> nums = new Stack<char>();
// iterate the input string
for(int i = 0; i < stringToEncode.Length; i++) {
char c = stringToEncode[i];
// we have 3 cases:
// 1) is alpha ==> convert using mapping
// 2) is number ==> peek ahead to complete the number
// 3) is special char / punctunation ==> ignore
if(Convert.ContainsKey(c)) {
sb.Append(Convert[c]);
continue;
}
if(Char.IsDigit(c)) {
nums.Push(c);
// we've reached the end of the input string OR
// we've reached the end of the number
if (i == stringToEncode.Length - 1
|| !Char.IsDigit(stringToEncode[i + 1])) {
while (nums.Count > 0) {
sb.Append(nums.Pop());
}
}
continue;
}
// not letter, not digit
sb.Append(c);
}
return sb.ToString();
}
// create our mappings for letters
private static void BuildConversionMappings() {
Convert = new Dictionary<char, char>();
// only loop once for both
for(char c = 'B'; c<='Z'; c++) {
// add capitals version
char val = (char)(c - 1);
val = Char.ToLower(val);
Convert.Add(c, val);
// add lower case version
Convert.Add(Char.ToLower(c),val);
}
// special cases
Convert['y'] = ' ';
Convert['Y'] = ' ';
Convert.Add(' ', 'y');
// vowels
char[] vowels = new char[] { 'a', 'e', 'i', 'o', 'u' };
for(int i = 0;i < vowels.Length;i++) {
var letter = vowels[i];
var value = (i+1).ToString()[0];
Convert[letter] = value;
Convert[Char.ToUpper(letter)] = value;
}
}
I was asked this question for an interview and the only feedback I received was building a dictionary was a very poor choice and they were no longer interested in continuing the application process. I was surprised and disappointed, but I want to improve for the next time. What should I do better?
Dictionary
would be exactly what I would choose for this task and hardly consider it "poor". \$\endgroup\$encode
and then all rules inside a single method... if a senior dev wrote this code I would send him home ;-] It's neither extendable nor maintainable. \$\endgroup\$