The obvious answer (at least in my eyes) would be to use .key(value) however I keep getting an error 'undefined method for key'. I have to return the key of the first instance of the highest value. This is what I've put in;
def high(x)
alphabet = Hash.new(0)
count = 0
("a".."z").each do |char|
alphabet[char] = count = 1
end
words = Hash.new(0)
x.split(" ").each do |word|
count_a = 0
word.each_char do |chars|
if alphabet.has_key?(chars)
count_a = alphabet[chars]
end
end
words[word] = count_a
end
highest = words.sort_by { |key, value| value }
(highest[0][1]..highest[-1][1]).each do |val|
if val == highest[-1][1]
return highest.key(val)
else
return highest[-1][0]
end
end
end
I know it's messy code (I'm only a few months into learning coding). The issue I'm facing is specifically in the following section;
highest = words.sort_by { |key, value| value }
(highest[0][1]..highest[-1][1]).each do |val|
if val == highest[-1][1]
return highest.key(val)
else
return highest[-1][0]
end
end
So where I write 'return highest.key(val)' I'm expecting it to return the word that is equal to the highest 'scoring' word, however it just gives me the undefined method error. Any help would be greatly appreciated.
CodePudding user response:
I managed to fix my problem! Once again, not very elegant code I know, however if someone else is having a similar issue this may help. (and thanks again to everyone who pointed out it was an array not a hash)
def high(x)
alphabet = Hash.new(0)
count = 0
("a".."z").each do |char|
alphabet[char] = count = 1
end
words = Hash.new(0)
x.split(" ").each do |word|
count_a = 0
word.each_char do |chars|
if alphabet.has_key?(chars)
count_a = alphabet[chars]
end
end
words[word] = count_a
end
highest = words.sort_by { |key, value| value }.to_h
highest_score = highest.values.last
best = []
highest.each_value do |value|
if value = highest_score
best << highest.key(value)
end
end
return best[0]
end
so the general idea behind this code is that the argument 'x' is a string and letters are scored a = 1 b = 2 etc. This code returns the word with the biggest score. If there's multiple words with the top score, it will return whichever one of those words came first.
CodePudding user response:
Using Enumerable and String Methods to Make Magic Happen
I'm glad you've already answered your own question. Meanwhile, if you don't care about tracking all the words as you go, or keeping a running list of how well each word scores, then you can make this a lot simpler, faster, and less memory-intensive by letting Ruby do more of the work for you and just return the highest-scoring item.
Ruby has a lot of built-in methods to make jobs like this easier, and its core methods are often highly optimized. Here's a solution with seven lines of code (excluding comments) that makes use of the Enumerable#zip, Enumerable#sum, and Enumerable#max_by methods inherited by Array to do most of the heavy lifting.
Hash#merge helps us take care of some edge cases likes spaces or dashes in compound words. Then, with a little help from String#chars and String#downcase!, it's almost like Ruby does it all for us!
In Ruby 3.0.2:
# Map your numerical score to each letter and store in a Hash.
#
# @note We can prepend a value of zero for spaces and other special
# characters, too!
ALPHA_SCORES = {" " => 0, "-" => 0}.merge (?a..?z).zip(1..26).to_h
# Convert all words to lowercase, and return the highest-scoring word
# and its score as an Array.
def find_highest_scoring_word_in *words
words.flatten.map do |word|
word.downcase!
[word, word.chars.sum { ALPHA_SCORES[_1] }]
end.max_by(&:last)
end
This approach provides a lot of flexibility. For example, you can call it in all of the following ways, and it will return the right result.
# pass a single Array of String objects
find_highest_scoring_word_in %w[foo bar baz]
#=> ["foo", 36]
# pass two Array of String arguments
find_highest_scoring_word_in %w[foo bar baz], %w[quux wuuble]
#=> ["wuuble", 84]
# pass in three separate String arguments
find_highest_scoring_word_in 'alpha', 'beta', 'gamma'
#=> ["alpha", 38]
# Pass in expressions that evaluate to a String. The first creates 100
# letter a's, and the second 4 z's. Since `z` is worth 26 points, and
# `a` only 1, it's "zzzz" for the win!
find_highest_scoring_word_in 'a' * 100, 'z' * 4
#=> ["zzzz", 104]