从数组和频率创建哈希

时间:2013-11-13 19:49:29

标签: ruby arrays hash

我有一个数组[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 }

8 个答案:

答案 0 :(得分:14)

执行以下操作:

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}

或者更多使用Enumerable#each_with_object的Rubyish:

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 = {}是空的,默认值为nilnilNilclass的实例,NilClass没有任何实例名为#+的方法。所以你得到NoMethodError

查看Hash::new文档:

new → new_hash
new(obj) → new_hash
  

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

答案 1 :(得分:9)

只需使用注射。这种类型的应用程序正是它的意思。 类似的东西:

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

答案 2 :(得分:9)

在Ruby 2.4 +中:

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

答案 3 :(得分:2)

爱我一些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} 

答案 4 :(得分:2)

这是一个使用Hash数组初始化程序

的简短选项
Hash[arr.uniq.map {|v| [v, arr.count(v)] }]

答案 5 :(得分:1)

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

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

答案 6 :(得分:1)

Ruby 2.7及更高版本将具有Enumerable#tally方法来解决此问题。

从后备箱documentation

  

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

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

答案 7 :(得分:0)

或者按方法使用组:

arr = [1,2,4,5,4,7]

Hash[arr.group_by{|x|x}.map{|num,arr| [num, arr.size] }]