views:

145

answers:

4

I am a perl person and I have made hashes like this for awhile:

my %date;

#Assume the scalars are called with 'my' earlier

$date{$month}{$day}{$hours}{$min}{$sec}++

Now I am learning ruby and I have so far found that using this tree is the way to do many keys and a value. Is there any way to use the simple format that I use with perl using one line?

 @date = {                                                                                                                                                                      
        month => {                                                                                                                                                                 
          day => {                                                                                                                                                                 
           hours => {                                                                                                                                                              
              min => {                                                                                                                                                             
                sec => 1                                                                                                                                                           
              }                                                                                                                                                                    
            }                                                                                                                                                                      
          }                                                                                                                                                                        
        }                                                                                                                                                                          

      }                   
A: 

Using symbols seemed to work:

ree-1.8.7-2009.10 > @date = {:month =>{:day => {:hours => {:min => {:sec => 1 } } } } }
 => {:month=>{:day=>{:hours=>{:min=>{:sec=>1}}}}} 

I can then retrieve the val like this:

ree-1.8.7-2009.10 > @date[:month][:day]
 => {:hours=>{:min=>{:sec=>1}}}
nicholasklick
Not a helpful answer.
friedo
Really? See above....
nicholasklick
Now that you've edited it I will remove my -1 :)
friedo
Thanks, I posted before completing my entry.....
nicholasklick
+1  A: 

It doesn't look like Ruby can do autovivification from the start, but you can easily add in that functionality. A search for "ruby autovivification" on Google gives:

http://t-a-w.blogspot.com/2006/07/autovivification-in-ruby.html

Which contains a decent example of how to create a hash that will work the way you are looking for.

http://stackoverflow.com/questions/1503671/ruby-hash-autovivification-facets might also be helpful.

Eric Strom
Thanks for those links. You get second place. I have learned a new word "autovivification."
ThomasG33K
+6  A: 

Unfortunately, there is no simple, practical way. A Ruby equivalent would be an ugly, ugly beast like:

((((@date[month] ||= {})[day] ||= {})[hours] ||= {})[min] ||= {})[sec] = 1

There is a way to assign default values for missing keys in hashes, though:

@date = Hash.new { |hash, key| hash[key] = {} }

# @date[:month] is set to a new, empty hash because the key is missing.
@date[:month][:day] = 1

Unfortunately this does not work recursively.

...unless you create it yourself; hooray for Ruby!

class Hash
  def self.recursive
    new { |hash, key| hash[key] = recursive }
  end
end

@date = Hash.recursive
@date[month][day][hours][min][sec] = 1
# @date now equals {month=>{day=>{hours=>{min=>{sec=>1}}}}}

Keep in mind, though, that all unset values are now {} rather than nil.

molf
Thanks for a great answer. One more thing. How would you go about storing parsed data? I use hashes in perl what is your take on storing categorized parsed data? (My other comment to my question post has more)
ThomasG33K
If you need the data available by month, by month + day, by month + day + hour, etc., then your approach is ok. If you need to do something else with it, then it really depends on your use case. You might even be fine just using an array like `[month, day, hours, min, sec]` or a simple string as hash key; but I can't say without knowing more.
molf
I also found I could stick in symbols easily by doing:@date[month.to_sym][day.to_sym][hours.to_sym][min.to_sym][sec.to_sym] =+ 1Anyway to stick that into that recursive function to auto sym keys?
ThomasG33K
@ThomasG33K, not really; you could subclass `Hash` and auto-convert your keys to symbols, or you can use `ActiveSupport::HashWithIndifferentAccess` if you can afford a dependency on activesupport (a Rails component). Sticking it in the recursive method above will only work when the `Hash` is created, not when you access its keys.
molf
A: 

You can use the Facets gem's Hash.autonew to do the same thing as the recursive function given in Molf's answer.

Ken Bloom