I was creating a ruby programme that will calculate the frequency of each letter appearing in my text and will be return it as a Hash.
Below is my code:
class LetterHistogram
attr_reader :letters
attr_accessor :text
def initialize(t = "Hello World!")
@text = t
end
def display
calculateFrequencies
("A".."Z").each {|x| puts "#{x}: " + "*" * letters[x]}
end
private
attr_writer :letters
def calculateFrequencies
calcuFreq = String.new(text)
calcuFreq.upcase!.gsub!(/\W+/, '')
letters.clear
letters.default = 0
calcuFreq.each_char {|char| letters[char] += 1}
end
end
But I getting this error when I run the display method enter image description here
What is the error means and how to solve it?
The main problem is that in calculateFrequencies
you are using a not assigned variable: letters
. So, when you call calculateFrequencies
in display
, letters = nil
and calling .clear
on nil
returns the error.
This is a modified version of the code, using snake_case (which is the Ruby writing standard).
class LetterHistogram
attr_accessor :text
def initialize(t = "Hello World!")
@text = t
end
def display
calculate_frequencies.each { |letter, freq| puts "#{letter}: #{freq}"}
end
private
def calculate_frequencies
freq = @text.upcase.gsub!(/\W+/, '').each_char.with_object(Hash.new(0)) { |letter, freq| freq[letter] += 1 }
freq.sort_by{ |letter, freq| freq }.reverse # just to sort
end
end
Instantiating an object and calling .display
on it:
senctence = LetterHistogram.new
senctence.display
#=> L: 3
#=> O: 2
#=> D: 1
#=> R: 1
#=> W: 1
#=> E: 1
#=> H: 1
How it works
For calculating the frequency I used a Hash populated by: https://ruby-doc.org/core-2.5.1/Enumerable.html#method-i-each_with_object
Printing out freq
from calculate_frequencies
you can see it:
#=> {"H"=>1, "E"=>1, "L"=>3, "O"=>2, "W"=>1, "R"=>1, "D"=>1}
freq
hash with all values to 0, then update the hash, something like this:
freq = ("A".."Z").each_with_object({}) { |letter, freq| freq[letter] = 0 }
"Hello World!".upcase.gsub!(/\W+/, '').each_char { |letter| freq[letter] += 1 }
#=> {"A"=>0, "B"=>0, "C"=>0, "D"=>1, "E"=>1, "F"=>0, "G"=>0, "H"=>1, "I"=>0, "J"=>0, "K"=>0, "L"=>3, "M"=>0, "N"=>0, "O"=>2, "P"=>0, "Q"=>0, "R"=>1, "S"=>0, "T"=>0, "U"=>0, "V"=>0, "W"=>1, "X"=>0, "Y"=>0, "Z"=>0}
Finally, to print out the istogram:
freq.each { |letter, freq| puts "#{letter}: " + "◼︎" * freq if freq > 0 }
#=> D: ◼︎
#=> E: ◼︎
#=> H: ◼︎
#=> L: ◼︎◼︎◼︎
#=> O: ◼︎◼︎
#=> R: ◼︎
#=> W: ◼︎