【问题标题】:frequency of a letter in a string字符串中字母的频率
【发布时间】:2014-06-19 19:08:24
【问题描述】:

在尝试查找“fantastic”中字母的频率时,我无法理解给定的解决方案:

def letter_count(str)
  counts = {}

  str.each_char do |char|
    next if char == " "
    counts[char] = 0 unless counts.include?(char)
    counts[char] += 1
  end

  counts
end

我尝试解构它,当我创建以下代码时,我希望它会做完全相同的事情。但是它给了我不同的结果。

blah = {}
x = 'fantastic'
    x.each_char do |char|
        next if char == " "
        blah[char] = 0 
            unless 
            blah.include?(char)
            blah[char] += 1
    end
blah
end

第一段代码给了我以下内容

puts letter_count('fantastic')
>
{"f"=>1, "a"=>2, "n"=>1, "t"=>2, "s"=>1, "i"=>1, "c"=>1}

为什么第二段代码给我

puts blah
>
{"f"=>0, "a"=>0, "n"=>0, "t"=>0, "s"=>0, "i"=>0, "c"=>0}

谁能分解代码片段并告诉我潜在的区别是什么。我想一旦我理解了这一点,我将能够真正理解第一段代码。此外,如果您想解释一下第一段代码以帮助我,那也很棒。

【问题讨论】:

    标签: ruby hash iterator each


    【解决方案1】:

    既然@Steve 已经回答了你的问题并且你已经接受了他的回答,也许我可以建议另一种计算字母的方法。这只是可以采取的众多方法之一。

    代码

    def letter_count(str)
      str.downcase.each_char.with_object({}) { |c,h|
        (h[c] = h.fetch(c,0) + 1) if c =~ /[a-z]/ }
    end
    

    示例

    letter_count('Fantastic')
      #=> {"f"=>1, "a"=>2, "n"=>1, "t"=>2, "s"=>1, "i"=>1, "c"=>1}
    

    说明

    这就是正在发生的事情。

    str = 'Fantastic'
    

    我们使用String#downcase,例如,'f''F' 在计数时被视为同一个字符。 (如果你不想这样,只需删除 .downcase。)让

    s = str.downcase #=> "fantastic"
    

    s.each_char.with_object({}) { |c,h| (h[c] = h.fetch(c,0) + 1) c =~ /[a-z]/ }
    

    枚举器String#each_char 链接到Enumerator#with_index。这将创建一个复合枚举器:

    enum = s.each_char.with_object({})
      #=> #<Enumerator: #<Enumerator: "fantastic":each_char>:with_object({})>
    

    我们可以通过将枚举器转换为数组来查看枚举器将传递给块的内容:

    enum.to_a
      #=> [["f", {}], ["a", {}], ["n", {}], ["t", {}], ["a", {}],
      #    ["s", {}], ["t", {}], ["i", {}], ["c", {}]]
    

    (实际上,它只使用'f' 传递一个空散列;然后它传递散列的更新值。)枚举器with_object 创建一个由块变量h 表示的空散列。

    传递给块的第一个元素enum 是字符串'f'。块变量c 被分配了那个值,所以块中的表达式:

    (h[c] = h.fetch(c,0) + 1) if c =~ /[a-z]/
    

    评估为:

    (h['f'] = h.fetch('f',0) + 1) if 'f' =~ /[a-z]/ 
    

    现在

    c =~ /[a-z]/
    

    true 当且仅当 c 是小写字母。这里

    'f' =~ /[a-z]/ #=> true
    

    所以我们评估表达式

    h[c] = h.fetch(c,0) + 1
    

    h.fetch(c,0) 如果h 有一个键c,则返回h[c];否则返回Hash#fetch 的第二个参数的值,这里为零。 (fetch 也可以带块。)

    由于h现在是空的,它变成了

    h['f'] = 0 + 1 #=> 1
    

    枚举器each_char 然后将'a''n''t' 传递给块,导致哈希成为

    h = {'f'=>1, 'a'=>1, 'n'=>1, 't'=>1 }
    

    传入的下一个字符是第二个'a'。由于h 已经有一个密钥'a'

    h[c] = h.fetch(c,0) + 1
    

    评估为

    h['a'] = h['a'] + 1 #=> 1 + 1 => 2
    

    字符串的其余部分以相同的方式处理。

    【讨论】:

      【解决方案2】:

      你不能分割这条线...

      counts[char] = 0 unless counts.include?(char)
      

      ... 以您的方式跨越多行。尾随条件仅适用于单行。

      如果您想将其拆分为多行,则必须转换为传统的 if / end(在本例中为 /end)格式。

      unless counts.include?(char)
        counts[char] = 0
      end
      

      这里是代码的解释...

      # we define a method letter_count that accepts one argument str
      def letter_count(str)
      
        # we create an empty hash 
        counts = {}
      
        # we loop through all the characters in the string... we will refer to each character as char
        str.each_char do |char|
      
          # we skip blank characters (we go and process the next character)
          next if char == " "
      
          # if there is no hash entry for the current character we initialis the 
          # count for that character to zero
          counts[char] = 0 unless counts.include?(char)
      
          # we increase the count for the current character by 1
          counts[char] += 1
      
        # we end the each_char loop
        end
      
        # we make sure the hash of counts is returned at the end of this method 
        counts
      
      # end of the method
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-25
        • 2017-08-30
        • 2018-09-08
        • 2021-12-31
        • 2012-06-04
        • 2017-04-20
        • 2016-07-25
        相关资源
        最近更新 更多