Problem overview
The method convertToHackerSpeak receives a string, input, and returns a coded version. Five letters are replaced by digits: a becomes 4, e becomes 3, i becomes 1, o becomes 0 and s becomes 5. Every other character stays as it is.
For "javascript is cool" the result is "j4v45cr1pt 15 c00l": the two a letters become 4, the s becomes 5, the i becomes 1, and the o pair becomes 00. For "become a coder" the result is "b3c0m3 4 c0d3r".
Approach: build a new string character by character
Strings in TypeScript are immutable: you can't change a character in place, and the compiler rejects an assignment such as input[4] = "4" with the message Index signature in type 'String' only permits reading. So the method builds a second string. It starts empty, visits every character of input in order, and appends either the replacement digit or the original character. At the end it returns the new string.
For each character exactly one thing is appended: the checks form a chain, and the first one that matches decides. A character that matches none of the five letters falls through to the last branch and is copied unchanged, which covers spaces, punctuation, digits and every other letter.
Here is the start of a trace for "become a coder". The first character, b, matches none of the five letters, so solution becomes "b". Next, e matches the second test, so solution becomes "b3". Then c is copied, giving "b3c", and o becomes 0, giving "b3c0". The space between the words is copied like any other non-matching character. The order of the five tests does not change the result, because a character can equal only one of the five letters.
Step by step
- Declare
solutionas an empty string, withlet, because+=assigns a new value each time. Withconst, the first append would be an error. - Loop over
inputwithfor...of. The constantcholds one character per pass. TypeScript has no separate character type, socis a string of length one. - Handle
"a". Ifc === "a", append"4". - Handle
"e"with anelse if. It is checked only when the first test failed, and it appends"3". - Handle
"i", appending"1". - Handle
"o", appending"0". - Handle
"s", appending"5". - Finish the chain with
else. Any other character is appended unchanged. - Return
solutionafter the loop, when every character has been processed.
The solution in TypeScript
class Solution {
convertToHackerSpeak(input: string): string {
let solution: string = "";
for (const c of input) {
if (c === "a") {
solution += "4";
} else if (c === "e") {
solution += "3";
} else if (c === "i") {
solution += "1";
} else if (c === "o") {
solution += "0";
} else if (c === "s") {
solution += "5";
} else {
solution += c;
}
}
return solution;
}
}
A few TypeScript points:
- Immutability.
solution += "4"doesn't change the existing string. It creates a new one and stores it insolution. The code reads like appending, and the engine handles the cost well, so for a task of this size it is the natural way to build a string. for...ofover a string visits one character at a time, in order.for...inwould give the indices instead.- Characters beyond the basic set.
for...ofwalks a string by code point, so an emoji counts as one pass of the loop even though it occupies two positions inlength. For"a😀b"the loop runs 3 times whilelengthis 4. Such characters are copied unchanged by the finalelse, which is the behaviour you want. - Case matters.
"A"is a different string from"a", so capital letters are copied unchanged. The statement lists only lowercase letters. - Use
===for comparison, as in the rest of the course. It compares values without converting types. - Annotations are erased.
input: stringand: stringhelp the compiler and disappear in the JavaScript.
A table-driven version
The five-branch chain is the most direct way to write the lesson. Once you're comfortable with it, you can see that the five branches differ only in data, and an object can hold the data instead:
const codes: Record<string, string> = { a: "4", e: "3", i: "1", o: "0", s: "5" };
function convert(text: string): string {
let result = "";
for (const c of text) {
result += codes[c] ?? c;
}
return result;
}
Here codes[c] is undefined for a character that has no entry, and the ?? operator then uses c instead. It gives the same results: convert("javascript is cool") returns "j4v45cr1pt 15 c00l", and convert("become a coder") returns "b3c0m3 4 c0d3r". Adding a sixth letter means adding one entry rather than one more branch. The lesson asks for the explicit chain, so submit that one.
Complexity
Time: O(n), where n is the length of input. Each character is visited once and checked against at most five letters, which is a constant amount of work.
Space: O(n). The result string has the same length as the input.
Edge cases and common mistakes
- The empty string. The loop does not run, and the method returns
"". - Using a chain of separate
ifstatements instead ofelse if. A character could then be appended twice: the finalelsewould also fire for letters that were already replaced. - Forgetting the final
else. Characters that aren't replaced would be dropped from the result. - Trying to modify the input. Assigning to
input[i]is a compile error and can't change the string. Build a new one instead. - Replacing capital letters.
"Apple"becomes"Appl3", not"4ppl3". Only lowercaseeis replaced. - Returning inside the loop, which would stop after the first character.
Testing
"javascript is cool"gives"j4v45cr1pt 15 c00l"."programming is fun"gives"pr0gr4mm1ng 15 fun"."become a coder"gives"b3c0m3 4 c0d3r".""gives"".