簡體   English   中英

Ruby:如何計算字母的頻率

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM