Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a new hash with default keys

I want to create a hash with an index that comes from an array.

ary = ["a", "b", "c"]
h = Hash.new(ary.each{|a| h[a] = 0})

My goal is to start with a hash like this:

h = {"a"=>0, "b"=>0, "c"=>0}

so that later when the hash has changed I can reset it with h.default

Unfortunately the way I'm setting up the hash is not working... any ideas?

like image 209
Jeremy Smith Avatar asked May 06 '11 18:05

Jeremy Smith


People also ask

How do you initialize a hash?

Another initialization method is to pass Hash. new a block, which is invoked each time a value is requested for a key that has no value. This allows you to use a distinct value for each key. The block is passed two arguments: the hash being asked for a value, and the key used.

How might you specify a default value for a hash?

From the doc, setting a default value has the following behaviour: Returns the default value, the value that would be returned by hsh if key did not exist in hsh. See also Hash::new and Hash#default=. Therefore, every time frequencies[word] is not set, the value for that individual key is set to 0.

How do you create a new hash in Ruby?

In Ruby you can create a Hash by assigning a key to a value with => , separate these key/value pairs with commas, and enclose the whole thing with curly braces.


5 Answers

Use the default value feature for the hash

h = Hash.new(0)

h["a"]      # => 0

In this approach, the key is not set.

h.key?("a") # => false

Other approach is to set the missing key when accessed.

h = Hash.new {|h, k| h[k] = 0}
h["a"]      # => 0
h.key?("a") # => true

Even in this approach, the operations like key? will fail if you haven't accessed the key before.

h.key?("b") # => false
h["b"]      # => 0
h.key?("b") # => true

You can always resort to brute force, which has the least boundary conditions.

h = Hash.new.tap {|h| ["a", "b", "c"].each{|k| h[k] = 0}}
h.key?("b") # => true
h["b"]      # => 0
like image 97
Harish Shetty Avatar answered Nov 01 '22 13:11

Harish Shetty


You should instantiate your hash h first, and then fill it with the contents of the array:

h = {}    
ary = ["a", "b", "c"]
ary.each{|a| h[a] = 0}
like image 33
McStretch Avatar answered Nov 01 '22 13:11

McStretch


You can do it like this where you expand a list into zero-initialized values:

list = %w[ a b c ]

hash = Hash[list.collect { |i| [ i, 0 ] }]

You can also make a Hash that simply has a default value of 0 for any given key:

hash = Hash.new { |h, k| h[k] = 0 }

Any new key referenced will be pre-initialized to the default value and this will avoid having to initialize the whole hash.

like image 41
tadman Avatar answered Nov 01 '22 15:11

tadman


This may not be the most efficient way, but I always appreciate one-liners that reveal a little more about Ruby's versatility:

h =  Hash[['a', 'b', 'c'].collect { |v|  [v, 0] }]

Or another one-liner that does the same thing:

h = ['a', 'b', 'c'].inject({}) {|h, v| h[v] = 0; h }

By the way, from a performance standpoint, the one-liners run about 80% of the speed of:

h = {}
ary = ['a','b','c']
ary.each { |a| h[a]=0 }
like image 37
Kelly Avatar answered Nov 01 '22 14:11

Kelly


Rails 6 added index_with on Enumerable module. This will help in creating a hash from an enumerator with default or fetched values.

ary = %w[a b c]
hash = ary.index_with(0) # => {"a"=>0, "b"=>0, "c"=>0}
like image 40
Simon Isler Avatar answered Nov 01 '22 14:11

Simon Isler