Friday, May 6, 2011

Better way to fill a Ruby hash?

Is there a better way to do this? (it looks clunky)

form_params = {}
form_params['tid'] = tid
form_params['qid'] = qid
form_params['pri'] = pri
form_params['sec'] = sec
form_params['to_u'] = to_u
form_params['to_d'] = to_d
form_params['from'] = from
form_params['wl'] = wl
From stackoverflow
  • form_params = { "tid" => tid, "qid" => qid }
    

    Or you could do

    form_params = Hash["tid", tid, "qid", qid]       #=> {"tid"=>tid, "qid"=>qid}
    form_params = Hash["tid" => tid, "qid" => qid]   #=> {"tid"=>tid, "qid"=>qid}
    form_params = Hash[tid => tid, qid => qid]       #=> {"tid"=>tid, "qid"=>qid}
    

    (nb. the last one is new for 1.9 and it makes your key symbols instead of strings)

    {tid:tid, qid:qid}

    Keys and values occur in pairs, so there must be an even number of arguments.

    Chuck : As of Ruby 1.9, if you're OK with the keys being symbols rather than strings, you can also say {tid:tid, qid:qid}.
    Schildmeijer : : doesn't work, => does
    Chuck : No, the colon works just as I said. I just tested. ruby -e "tid=12; puts({tid:tid})" prints "{:tid=>12}". The => form does not work -- it prints {12=>12}.
    Schildmeijer : aha, now I see the different
    kolrie : Side note: the "hash from arrays" method won't work on 1.9.
  • If performance is not important this one might look better:

    form_params = {}
    ['tid', 'qid', 'pri', 'sec', 'to_u', 'to_d', 'from', 'wl'].each do |v|
      form_params[v] = eval(v)
    end
    

    If those names are actually methods you can replace eval by the faster send:

    form_params[v] = send(v.to_sym)
    

    (Update) An alternative (and more elegant) way using inject:

    form_params = ['tid', 'qid', 'pri', 'sec', 'to_u', 'to_d', 'from', 'wl'].inject({}) { |h, v| h[v] = send(v); h }
    
  • I created a custom class called MoreOpenStruct to deal with Hash's lack of aesthetics, and using that class, your example would look like:

    form_params = MoreOpenStruct.new
    form_params.tid = tid
    form_params.qid = qid
    form_params.pri = pri
    form_params.sec = sec
    form_params.to_u = to_u
    form_params.to_d = to_d
    form_params.from = from
    form_params.wl = wl
    
    form_params_hash = form_params._to_hash
      #=> { :tid => tid, :qid => qid, etc }
    

    If you need string literals rather than symbols as the key to your hash then a couple more tweaks are required.

    I use my custom struct class when I want easy to read/manipulate Hashes, but if all you're doing is an assignment and don't need to parse the hash beyond that, I'd use Roger's solution.

  • Slight modification to the above, since your example had string keys:

    form_params = {}
    %w(tid qid pri sec to_u to_d from wl).each{|v| form_params[v] = send(v)}
    
  • The other options would be to create a Struct based class to store those values in. For example:

    FormParams = Struct.new(:tid, :qid, :pri, :sec, :to_u, :to_d, :from, :wl)
    

    Then you'd be able to initialise the form_params instance in a variety of ways:

    form_params = FormParams.new(:tid => tid, :qid => qid, # etc ...
    form_params = FormParams.new(tid, qid, pri, sec, to_u, to_d, from, wl)
    form_params = FormParams.new
    form_params.tid = tid
    form_params.gid = gid
    # etc ...
    

0 comments:

Post a Comment