Building things that matter
blake-connally-373084.jpg

Code Challenges

Highest Scoring Word (Ruby)

Got bored this afternoon so went back to CodeWars and tackled the Highest Scoring Word challenge.

Challenge

Given a string of words, you need to find the highest scoring word.
Each letter of a word scores points according to it's position in the alphabet: a = 1, b = 2, c = 3 etc.
You need to return the highest scoring word as a string.
If two words score the same, return the word that appears earliest in the original string.
All letters will be lowercase and all inputs will be valid.

My Solution

I worked through this a bit slower than many other solutions, and my solution is a bit more complex, but I think more appropriate if considering this a real world issue. One of the biggest ways that my solution differed from other solutions was how I created the scoring key.

I set a hash as my score key, whereas almost all the other solutions I saw utilized an effective, yet complex, way of matching letters with their position in the alphabet. Something like: 

@scores ||= ("a".."z").to_a.map.with_index(1) {|let, i| [let, i]}.to_h

My challenge with this approach is that is not flexible in the event you ever need to change the scoring of an individual word, this solution doesn't allow that.  This locks your scoring key into being 1 to 1 and, if in the future the value of individual letters needs to change, you'd have to come up with a different solution. 

I have worked on apps where scoring criteria changes annually, so that was one reason for my approach.  With my approach you have the ability to change scores for individual letters at a very granular level, and also be able to see clearly what each letter is scored as in the event of a scoring dispute. 

From here I created two additional methods (single responsibility!) to perform the two main steps of the main method, score the individual words and return the highest scoring word (and if there are two with the same score, return the first one that appears).

The score_words method takes the word being scored, and the score_key as parameters, splits the word into individual letters, matches that letter with it's score in the score_key pushes that value into an array that is then summed and returned. 

This method is then used in the main high method once the words have been split, and here is where I decided to have more fun with hashes.  If I haven't mentioned it before, Hashes are my new favorite data collection. 

As part of my master variables I created an empty hash of word_scores.  My intention here is to have a hash of hashes that hold the scores from each word, where the word would be the key, and the value would be a hash that held the word's score and it's index position.

Storing it's index position was my way of solving for returning the first word that appears in the array in the even that there are two words with the same score.

This enables me to now have a hash for each word that looks like this:

word: {score: 10, index: 0}

By adding these individual hashes to the word_scores hash I now have a hash that I can not only use to determine which word has the score, but also can tell me which word has the earliest index position in the event two have the same score, allowing me to return the earlier value as the result.

word_scores: {
      word_one: {score: 20, index: 0},
      word_two: {score: 10, index: 1},
      word_three: {score: 20, index: 2}
}

In the case of the words above, word_one would be returned as the highest scoring word because our next method will not only identify 20 as the highest score, but it will identify that word_one's index value is lower than word_three and return it as the solution. 

As mentioned above, highest_score, is the second custom method I build and it's only job is to look at that hash so scored words and return the one with the highest score, and, if there are two with the same score, return the one with the lowest index position.

The first thing this method does is identify the highest score across all the scored words in the hash.  It doesn't care how many words have that score at this point, it just wants to know the highest score.

After getting the highest score, we ask it to select the words with the highest score, which, if there is only one then it only returns one, if there is more than one it will return all of them.  Because we had previously attached the index position as part of the value hash for the word, our final step is to look at the selected objects and pull the one with the smallest index number and return it as the solution. 

The highest_score method is broken out a bit more than it needs to be for clarity.  Because of the nature of rails, we can actually call the select and min_by actions in a daisy chain, but for clarify of exactly what this method is doing, I broke it into three separate steps (find high score, select all the words with that score, return the word with the lowest index) which make it easier to see what the method is doing and reason about it if debugging becomes necessary.

After this, we use these two additional methods in our main method and solve for the highest scoring word.  

Robert Cornell