[英]Ruby: how to count the frequencies of the letters
幫助:做一個頻率方法:計算每個字母出現在“str”中的頻率,並將輸出分配給“letters”。 該方法應將小寫和大寫視為同一個字母。 但我有關於 NoMethodError: undefined method 的錯誤 謝謝
這是我的代碼
class MyString
attr_accessor :str
attr_reader :letters
def initialize
@str = "Hello World!"
@letters = Hash.new()
end
def frequency
@letters = @str.split(" ").reduce(@letters) { |h, c| h[c] += 1; h}
end
def histogram
#@letters.each{|key,value| puts "#{key} + ':' + value.to_s + '*' * #{value}" }
end
end
錯誤顯示:
irb(main):009:0> txt1.frequency
NoMethodError: undefined method `+' for nil:NilClass
from assignment.rb:11:in `block in frequency'
from assignment.rb:11:in `each'
from assignment.rb:11:in `reduce'
from assignment.rb:11:in `frequency'
from (irb):9
from /usr/bin/irb:12:in `<main>'
當您嘗試將1
添加到不存在的哈希值時,它會嘗試將1
添加到nil
,這是不允許的。 您可以更改哈希值,使默認值為0
,而不是nil
。
@letters = Hash.new(0)
現在,您的程序現在正在計算單詞頻率,而不是字母頻率( split(" ")
在空格上拆分,而不是在每個字符上拆分)。 要拆分每個字符,請使用適當命名的each_char
方法。
@letters = @str.each_char.reduce(@letters) { |h, c| h[c] += 1; h}
每當使用計數哈希(@Silvio 的答案)時,您都可以改用Enumerable#group_by ,這就是我在這里所做的。
str = "It was the best of times, it was the worst of times"
str.gsub(/[[:punct:]\s]/, '').
downcase.
each_char.
group_by(&:itself).
each_with_object({}) { |(k,v),h| h[k] = v.size }
#=> {"i"=>4, "t"=>8, "w"=>3, "a"=>2, "s"=>6, "h"=>2, "e"=>5,
# "b"=>1, "o"=>3, "f"=>2, "m"=>2, "r"=>1}
步驟如下。
a = str.gsub(/[[:punct:]\s]/, '')
#=> "Itwasthebestoftimesitwastheworstoftimes"
b = a.downcase
#=> "itwasthebestoftimesitwastheworstoftimes"
e = b.each_char
#=> #<Enumerator: "itwasthebestoftimesitwastheworstoftimes":each_char>
f = e.group_by(&:itself)
#=> {"i"=>["i", "i", "i", "i"],
# "t"=>["t", "t", "t", "t", "t", "t", "t", "t"],
# ...
# "r"=>["r"]}
f.each_with_object({}) { |(k,v),h| h[k] = v.size }
#=> < return value shown above >
讓我們更仔細地看一下最后一步。 散列f
的第一個鍵值對作為一個二元素數組與散列h
的初始值一起傳遞給區塊:
(k,v), h = [["i", ["i", "i", "i", "i"]], {}]
#=> [["i", ["i", "i", "i", "i"]], {}]
應用消歧(或分解)規則,我們得到以下結果。
k #=> "i"
v #=> ["i", "i", "i", "i"]
h #=> {}
執行塊計算:
h[k] = v.size
#=> h["i"] = 4
所以現在
h => { "i"=>4 }
下一個鍵值對與h
的當前值一起傳遞給塊:
(k,v), h = [["t", ["t", "t", "t", "t", "t", "t", "t", "t"]], { "i"=>4 }]
#=> [["t", ["t", "t", "t", "t", "t", "t", "t", "t"]], {"i"=>4}]
k #=> "t"
v #=> ["t", "t", "t", "t", "t", "t", "t", "t"]
h #=> {"i"=>4}
h[k] = v.size
#=> 8
所以現在
h #=> {"i"=>4, "t"=>8}
其余計算類似。
方法Enumerable#tally在 Ruby v2.7 中首次亮相,專門為此任務構建:
str.gsub(/[[:punct:]\s]/, '').downcase.each_char.tally
#=> {"i"=>4, "t"=>8, "w"=>3, "a"=>2, "s"=>6, "h"=>2,
# "e"=>5, "b"=>1, "o"=>3, "f"=>2, "m"=>2, "r"=>1}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.