Problem overview
The method convertToHackerSpeak receives a string and returns a coded copy in which 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". For "become a coder" it is "b3c0m3 4 c0d3r".
Approach: build a new string
A Swift String is a value that you can't patch one character at a time by position. Instead, create an empty result and go through the input character by character. For each one, decide what to append: the digit for a special letter, or the character itself. This is one pass over the input.
Only lowercase letters are replaced. An uppercase A is a different character from a, so it passes through unchanged.
A tempting alternative is a chain of replacement calls, one per letter. That reads the whole string five times and is easy to get wrong when one replacement produces text another one matches. Here the replacement digits are never re-examined, because each input character is looked at once. A dictionary from letter to digit would shorten the code, but the explicit chain keeps every rule visible and practises else if.
Trace "a cat". The characters are a, a space, c, a and t. The first a matches the first branch and appends 4. The space matches none of the five tests and reaches the else, which copies it. c is copied, the second a becomes 4, and t is copied. The result is "4 c4t".
The order of the tests doesn't change the result, since each test looks at a different letter and at most one of them can be true for a given character. The order only decides how many comparisons a character costs before it is handled.
Step by step
- Create the result.
var solution = ""is a mutable empty string, since it grows. - Loop over the characters.
for c in inputgives each element as aCharacter. - Test for
"a". Ifc == "a", append"4". - Chain the other letters with
else if:"e"gives"3","i"gives"1","o"gives"0","s"gives"5". Only one branch runs for each character. - Default case. In the final
else, append the character unchanged withString(c). - Return
solutionafter the loop.
The solution in Swift
class Solution {
func convertToHackerSpeak(_ input: String) -> String {
var solution = ""
for c in 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 += String(c)
}
}
return solution
}
}
Swift details worth knowing:
CharacterversusString. Looping over a string yieldsCharactervalues. Swift has no single-quote literals:"a"is written with double quotes and becomes aCharacterwhen compared withc, or aStringwhen added tosolution. The context decides.- Why
String(c). The operator+=on aStringneeds anotherString. Writingsolution += cwith aCharacterdoes not compile: Swift cannot convert a value of typeCharacterto the expected argument typeString. - No indexing by integer.
input[4]is not allowed on aString, because characters have different sizes in memory. Looping withforavoids the problem. - Unicode. A
Characteris one user-perceived character, so letters with accents or emoji are treated as single units and pass through unchanged. - Value semantics.
solutionis its own string. Changing it never affectsinput.
A shorter version with a dictionary
Once the chain works, the same rules fit in a lookup table. A dictionary subscript returns an optional, which is nil for a missing key, and the ?? operator supplies a fallback for that case:
let codes: [Character: String] = ["a": "4", "e": "3", "i": "1", "o": "0", "s": "5"]
func convert(_ input: String) -> String {
var solution = ""
for c in input {
solution += codes[c] ?? String(c)
}
return solution
}
For "javascript is cool" this returns "j4v45cr1pt 15 c00l", the same as the lesson's version. Accented letters such as the two é in "été" are different characters from e and stay unchanged, and an emoji passes through as a single character: "a🙂s" becomes "4🙂5". Adding a new rule is one more entry in the table. For the lesson itself, write the explicit chain of comparisons the steps describe.
Complexity
Time: O(n), where n is the length of input. Each character is examined once, and at most five comparisons run for it, which is constant work.
Space: O(n). The result string ends up with exactly as many characters as the input.
Edge cases and common mistakes
- Empty input. The loop does nothing and the function returns
"". - Uppercase letters.
"Alice"becomes"Al1c3": the capitalAis not replaced. - Spaces and punctuation. They reach the final
elseand are copied. - Using separate
ifstatements. A chain of plainifs with anelseonly on the last one would copy special letters as well, because thatelsewould pair with the lastifalone. - Adding the wrong digit. The mapping is easy to mix up: the digits are 4, 3, 1, 0 and 5 for a, e, i, o and s. Check each branch against the table in the task, and note that 2, 6, 7, 8 and 9 never appear.
- Forgetting the default. Without the final
else, letters likejandvwould vanish.
Testing
Try these inputs in the editor above, and compare each result with the expected output.
"javascript is cool"gives"j4v45cr1pt 15 c00l"."become a coder"gives"b3c0m3 4 c0d3r"."Alice"gives"Al1c3".""gives"".
