Reputation: 45
I have an array with some different data (in string format) and I would like to count the frequencies of each value and store it in hash/dictonary, but i'm getting error trying to do it.
I would like to do something like this:
words = ["foo", "var", "spam", "egg", "foo", "foo", "egg"]
frequency = {}
words.each{|word| frequency[word] += 1}
and get the following output:
puts(frequency) #{"foo" => 3, "var" => 1, "spam" => 1, "egg" => 2}
but I'm getting the following problem:
prueba.rb:3:in `block in <main>': undefined method `+' for nil:NilClass (NoMethodError)
Is there another way of accomplishing the same result?
Upvotes: 1
Views: 46
Reputation: 13014
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 is the enumerator which iterates by passing each element with an object supplied (here Hash.new(0)
) and returns that supplied object in next iteration.
Hash.new(0)
creates a hash where default value of any key is 0.
hash = Hash.new(0)
hash['a'] #=> 0
We use this property of default value and simply pass each word to the object and increment the counter. :)
Issue in your code: You don't have default value in your case, so you would need to do that manually by checking if a key exists in the hash or not.
Upvotes: 1
Reputation: 1473
When you write:
words.each{|word| frequency[word] += 1}
It's equivalent to:
words.each{|word| frequency[word] = frequency[word] + 1}
However, frequency
hash is empty and frequency[word]
returns nil
-- essentially, you are trying to do nil + 1
, which results in the error you are getting.
You can initialize new elements of the hash manually:
words.each{|word| frequency[word] ||= 0; frequency[word] += 1}
Or, as other answers have already suggested, use frequency = Hash.new(0)
as a shortcut.
Upvotes: 1
Reputation: 141
You can use this. By initializing it with 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}
Upvotes: 0
Reputation: 30056
If you query the hash for a key not present you get nil
, that's the problem. Let's make 0
the default if a key is not present
frequency = Hash.new(0)
Upvotes: 4