【问题标题】:Create hash from array and frequency从数组和频率创建哈希
【发布时间】:2013-11-13 19:49:29
【问题描述】:

我有一个数组[1,2,4,5,4,7],我想找到每个数字的频率并将其存储在哈希中。我有这段代码,但它返回NoMethodError: undefined method '+' for nil:NilClass

def score( array )
  hash = {}
  array.each{|key| hash[key] += 1}
end

想要的输出是

{1 => 1, 2 => 1, 4 => 2, 5 => 1, 7 => 1 }

【问题讨论】:

  • 先生,有些人建议使用注入(也称为 reduce),这很好,但您只需将 hash = {} 更改为 hash = Hash.new(0)。这告诉 Ruby 如果遇到hash[key] 在必须有值的上下文中(例如hash[key] += 1 或v = hash[key])并且哈希不包含键key,则将key=>0 添加到采取进一步行动之前的哈希值(例如hash[key] += 1)。另一方面,如果key 不在散列中,if hash[key] == 7 将评估为if nil == 7; key=>0 不会被添加到哈希中。
  • @CarySwoveland 很好的教学...!!喜欢它.. +1.
  • @tokland,问题可能是一样的,但不是问题。在这里,先生。想知道他为什么会出现特定错误,在我看来这很合理。
  • 很公平,那么我们就说它是相关的:) stackoverflow.com/questions/9480852/array-to-hash-words-count

标签: ruby arrays hash


【解决方案1】:

在 Ruby 2.4+ 中:

def score(array)
  array.group_by(&:itself).transform_values!(&:size)
end

【讨论】:

    【解决方案2】:

    如下操作:

    def score( array )
      hash = Hash.new(0)
      array.each{|key| hash[key] += 1}
      hash
    end
    score([1,2,4,5,4,7]) # => {1=>1, 2=>1, 4=>2, 5=>1, 7=>1}
    

    或者更多 Rubyish 使用 Enumerable#each_with_object:

    def score( array )
      array.each_with_object(Hash.new(0)){|key,hash| hash[key] += 1}
    end
    score([1,2,4,5,4,7]) # => {1=>1, 2=>1, 4=>2, 5=>1, 7=>1}
    

    NoMethodError: undefined method '+' for nil:NilClass的原因?

    hash = {}是一个空的has,默认值为nil。nil是Nilclass的一个实例,而NilClass没有任何称为#+的实例方法。所以你得到了NoMethodError。

    查看Hash::new 文档:

    new → new_hash
    new(obj) → new_hash
    

    返回一个新的空哈希。 如果此哈希随后被不对应于哈希条目的键访问,则返回的值取决于用于创建哈希的 new 的样式。在第一种形式中,访问返回 nil。如果指定了 obj,则此单个对象将用于所有默认值。 如果指定了一个块,它将使用哈希对象和键调用,并且应该返回默认值。如果需要,将值存储在哈希中是块的责任。

    【讨论】:

      【解决方案3】:

      从 Ruby 2.7 开始,Enumerable#tally 方法可以解决这个问题。

      来自后备箱documentation:

      统计集合。返回一个哈希值,其中键是元素,值是集合中与键对应的元素数。

      ["a", "b", "c", "b"].tally #=> {"a"=>1, "b"=>2, "c"=>1}
      

      【讨论】:

        【解决方案4】:

        只需使用注入。这种类型的应用程序正是它的用途。 比如:

        a.inject(Hash.new(0)) {|hash,word| hash[word] += 1; hash }
        

        【讨论】:

          【解决方案5】:

          爱我一些inject:

          results = array.inject(Hash.new(0)) {|hash, arr_element| hash[arr_element] += 1; hash }

          1.9.3p448 :082 > array = [1,2,4,5,4,7]
           => [1, 2, 4, 5, 4, 7] 
          1.9.3p448 :083 > results = array.inject(Hash.new(0)) {|hash, arr_element| hash[arr_element] += 1; hash }
           => {1=>1, 2=>1, 4=>2, 5=>1, 7=>1} 
          

          【讨论】:

          • 使用each_with_object:a.each_with_object(Hash.new(0)) { |e, h| h[e] += 1 }
          • 对于每个人来说,@muistooshort :)
          • 我倾向于将inject 用于“迭代并反馈”情况,each_with_object 用于“迭代和收集”情况。我厌倦了; hash 的东西。
          【解决方案6】:

          这是一个使用哈希数组初始值设定项的简短选项

          Hash[arr.uniq.map {|v| [v, arr.count(v)] }]
          

          【讨论】:

            【解决方案7】:

            这里的重点是 hash[1] 在数组中第一次看到 1 时并不存在 (nil)。

            您需要以某种方式对其进行初始化,hash = Hash.new(0) 是最简单的方法。在这种情况下,0 是您想要的初始值。

            【讨论】:

              【解决方案8】:

              或者使用分组方式:

              arr = [1,2,4,5,4,7]
              
              Hash[arr.group_by{|x|x}.map{|num,arr| [num, arr.size] }]
              

              【讨论】:

                猜你喜欢
                • 2011-04-20
                • 2011-05-08
                • 2012-03-27
                • 1970-01-01
                • 2012-06-29
                • 2018-01-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多