遍历数组以在哈希中生成频率的麻烦

时间:2019-05-16 11:27:12

标签: ruby

我有一个数组,其中包含一些不同的数据(字符串格式),我想计算每个值的频率并将其存储在哈希/字典中,但是尝试这样做会出错。

我想做这样的事情:

    words = ["foo", "var", "spam", "egg", "foo", "foo", "egg"]
    frequency = {}
    words.each{|word| frequency[word] += 1}

并获得以下输出:

   puts(frequency)   #{"foo" => 3, "var" => 1, "spam" => 1, "egg" => 2}

但是我遇到了以下问题:

    prueba.rb:3:in `block in <main>': undefined method `+' for nil:NilClass (NoMethodError)

还有另一种方法可以达到相同的结果吗?

4 个答案:

答案 0 :(得分:4)

如果您在哈希中查询不存在的密钥,则会得到nil,这就是问题所在。如果没有密钥,让我们将0设置为默认值

frequency = Hash.new(0)

答案 1 :(得分:1)

写时:

words.each{|word| frequency[word] += 1}

等效于:

words.each{|word| frequency[word] = frequency[word] + 1}

但是,frequency哈希为空,而frequency[word]返回nil-本质上,您正在尝试执行nil + 1,这会导致您得到错误。 / p>

您可以手动初始化哈希的新元素:

words.each{|word| frequency[word] ||= 0; frequency[word] += 1}

或者,正如其他答案已经建议的那样,使用frequency = Hash.new(0)作为快捷方式。

答案 2 :(得分:1)

words = ["foo", "var", "spam", "egg", "foo", "foo", "egg"]

words.each_with_object(Hash.new(0)) { |w, h| h[w] += 1 }
#=> {"foo"=>3, "var"=>1, "spam"=>1, "egg"=>2}

#each_with_object是枚举器,它通过将每个元素传递给提供的对象(此处为Hash.new(0))进行迭代,并在下一次迭代中返回该提供的对象。

Hash.new(0)创建一个哈希值,其中任何键的默认值为0。

hash = Hash.new(0)
hash['a'] #=> 0

我们使用默认值的此属性,只需将每个单词传递给对象并增加计数器。  :)

代码中的问题:您的情况下没有默认值,因此您需要通过检查哈希中是否存在键来手动执行此操作。

答案 3 :(得分:0)

您可以使用它。通过使用Hash.new(0)

对其进行初始化
names = ["foo", "var", "spam", "egg", "foo", "foo", "egg"]

names.inject(Hash.new(0)) { |total, e| total[e] += 1 ;total}

# {"foo"=>3, "var"=>1, "spam"=>1, "egg"=>2}