I recently started completing regular katas on CodeWars and other platforms to improve my programming skills. The katas are revealing in that they show you the most elegant/ cleanest solutions after you submit your own. What’s below is my original solution, the cleanest/ most upvoted solution, and an examination of the two.
The provided kata is called Replace With Alphabet Position and is presented as:
Welcome.
In this kata you are required to, given a string, replace every letter with its position in the alphabet.
If anything in the text isn’t a letter, ignore it and don’t return it.
”a” = 1, “b” = 2, etc.
Example
alphabetPosition("The sunset sets at twelve o' clock.");
When first thinking about a potential solution, I focused on determining the position of a letter in the alphabet. I originally thought to create an object containing each letter as a key and the corresponding position as the value {a:1, b:2}. However, since we are dealing with a simple sequence, an ordered list of letters in an array seemed more straightforward. Using the indexOf() method would quickly tell me if the value was in the list or not as well as the position. The resulting set of functions ultimately passed the tests and was straightforward enough to read. However, the solution was not terribly efficient and after looking at other solutions, I found that there was a fair bit to be desired.
As of the time of writing, @hencethus had the solution with the most Best Practices and Clever upvotes.
/* submitted by @hencethus */
functionalphabetPosition(text) {
return text
.toUpperCase()
.match(/[a-z]/gi)
.map((c) => c.charCodeAt() -64)
.join(" ");
}
After reviewing the solution from @hencethus, it was quickly apparent that my origial focus on the array of letters drove me down a path which produced more work than necessary. In short, my solution sought to address the requirements of the kata by performing the following operations:
Establish new, empty string
Loop content of text character by character
Determine index of each character in the array
If non-existent, return empty string, otherwise return index and a space
Trim new string to get rid of any leading or trailing spaces
In contrast, @hencethus tackled the problem in such a way that it reduced the amount of work from the very beginning and did not require any final cleanup (trim()) at the end.
Make all characters uppercase as “A” and “a” are both the first letter in the alphabet. This simplifies math later on
Match only letters a-z, as the solution does not need to worry about punctuation
Uppercase characters start at charCode 65, a simple subtraction of 64 produces the correct value
Create a new string from the array, separate values with a space
I subsequently amended my submission to remove excess characters right off the bat and changed the order of the ternary operator since the first outcome was expected.
const index = alphabetArray.indexOf(letter.toLowerCase());
return (index == -1) ? "" : " " + (index+1);
return (index >= 0) ? " " + (index+1) : "";
}
Comparing my orginal, my second, and @hencethus’ solutions, I found that the removal of excess characters had a large effect on the efficiency of the code. Compared to my original submission, the solution from @hencethus is 50% faster. As a means of comparison, I grabbed 4,500 words from Lorem Ipsum and ran each function 500 times.