0

I have an array:

values = [["branding", "color", "blue"],
          ["cust_info", "customer_code", "some_customer"],
          ["branding", "text", "custom text"]]

I am having trouble tranforming it to hash as follow:

{
"branding"  => {"color"=>"blue", "text"=>"custom text"},
"cust_info" => {"customer_code"=>"some customer"}
}
1
  • 1
    Array#inject is useful here. Basically, start with a new hash (passed into collect) and key adding to it each item. See blog.jayfields.com/2008/03/ruby-inject.html for a very similar example. Commented Aug 10, 2013 at 23:44

4 Answers 4

3

You can use default hash values to create something more legible than inject:

h = Hash.new {|hsh, key| hsh[key] = {}}
values.each {|a, b, c| h[a][b] = c}

Obviously, you should replace the h and a, b, c variables with your domain terms.

Bonus: If you find yourself needing to go N levels deep, check out autovivification:

fun = Hash.new { |h,k| h[k] = Hash.new(&h.default_proc) }
fun[:a][:b][:c][:d] = :e
# fun == {:a=>{:b=>{:c=>{:d=>:e}}}}

Or an overly-clever one-liner using each_with_object:

silly = values.each_with_object(Hash.new {|hsh, key| hsh[key] = {}}) {|(a, b, c), h| h[a][b] = c}
Sign up to request clarification or add additional context in comments.

Comments

1

Here is an example using Enumerable#inject:

values = [["branding", "color", "blue"],
          ["cust_info", "customer_code", "some_customer"],
          ["branding", "text", "custom text"]]

# r is the value we are are "injecting" and v represents each
# value in turn from the enumerable; here we create
# a new hash which will be the result hash (res == r)
res = values.inject({}) do |r, v|
    group, key, value = v     # array decomposition
    r[group] ||= {}           # make sure group exists
    r[group][key] = value     # set key/value in group
    r                         # return value for next iteration (same hash)
end

There are several different ways to write this; I think the above is relatively simple. See extracting from 2 dimensional array and creating a hash with array values for using a Hash (i.e. grouper) with "auto vivification".

3 Comments

what is the syntax of *v?
@pchu Whoops, I forget it (the "splat operator") is not required in Ruby to force array decomposition in an assignment. That will coerce the value to an Array on the RHS like that, but it's already an array .. corrected code. (Although group, key, value = *v is also legal in modern Ruby, it doesn't add any benefit in this case.)
Thanks it works. First time I see the splat operator. Cannot believe Ruby has an operator call splat.
0

Less elegant but easier to understand:

hash = {}
values.each do |value|
  if hash[value[0]] 
    hash[value[0]][value[1]] = value[2]
  else
    hash[value[0]] = {value[1] => value[2]}
  end
end

Comments

0
values.inject({}) { |m, (k1, k2, v)| m[k1] = { k2 => v }.merge m[k1] || {}; m }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.