Create hash from array and frequency

2019-03-16 07:07发布

I have an array [1,2,4,5,4,7] and I want to find the frequency of each number and store it in a hash. I have this code, but it returns NoMethodError: undefined method '+' for nil:NilClass

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

Desired output is

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

标签: ruby arrays hash
7条回答
贼婆χ
2楼-- · 2019-03-16 07:11

Just use inject. This type of application is exactly what it is meant for. Something like:

a.inject(Hash.new(0)) {|hash,word| hash[word] += 1; hash }
查看更多
老娘就宠你
3楼-- · 2019-03-16 07:15

The point here is that hash[1] doesn't exist (nil) when it first sees 1 in the array.

You need to initialize it somehow, and hash = Hash.new(0) is the easiest way. 0 is the initial value you want in this case.

查看更多
叼着烟拽天下
4楼-- · 2019-03-16 07:16

Here is a short option that uses the Hash array initializer

Hash[arr.uniq.map {|v| [v, arr.count(v)] }]
查看更多
我命由我不由天
5楼-- · 2019-03-16 07:30

Do as below :

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}

Or more Rubyish using 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}

The reason of why NoMethodError: undefined method '+' for nil:NilClass ?

hash = {} is an empty has,with default value as nil.nil is an instance of Nilclass,and NilClass doesn't have any instance method called #+. So you got NoMethodError.

Look at the Hash::new documentation :

new → new_hash
new(obj) → new_hash

Returns a new, empty hash. If this hash is subsequently accessed by a key that doesn’t correspond to a hash entry, the value returned depends on the style of new used to create the hash. In the first form, the access returns nil. If obj is specified, this single object will be used for all default values. If a block is specified, it will be called with the hash object and the key, and should return the default value. It is the block’s responsibility to store the value in the hash if required.

查看更多
虎瘦雄心在
6楼-- · 2019-03-16 07:33

In Ruby 2.4+:

def score(array)
  array.group_by(&:itself).transform_values!(&:size)
end
查看更多
仙女界的扛把子
7楼-- · 2019-03-16 07:34

Love me some 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} 
查看更多
登录 后发表回答