开发者

Ruby hash with array values

Say I have a hash like this

{"k1"=>["v1"], "k2"=>["v2"], "k3"=>["v3"], "k4"=>["v4"]}

And I want it to look like this:

{"k1"=>"v1", "k2"=>"v2", "k3"=>"v3", "k4"=>"v4"}

Is there a simpler way to do it than this ugly inject?

h1 = {"k1"=>["v1"], "k2"=>["v2"], "k3"=>["v3"], "k4"=>["v4"]}
h2 = h1开发者_StackOverflow社区.inject({}){|h,v| h[v.first]=v.last.first; h}


Somewhat less ugly than your "inject" solution:

h1 = {"k1"=>["v1"], "k2"=>["v2"], "k3"=>["v3"], "k4"=>["v4"]}
h2 = Hash[*h1.map.flatten]
h2 # => {"k1"=>"v1", "k2"=>"v2", "k3"=>"v3", "k4"=>"v4"}

As @the Tin Man points out in a comment, if your value arrays might have more than one element then you'll need to do something slightly different for it to work as expected:

h2 = Hash[*h1.map{|k,v|[k,v[0]]}.flatten]
h2 # => {"k1"=>"v1", "k2"=>"v2", "k3"=>"v3", "k4"=>"v4"}


You could modify it in-place with a simple each:

h = {"k1"=>["v1"], "k2"=>["v2"], "k3"=>["v3"], "k4"=>["v4"]}
h.each { |k,v| h[k] = v[0] }

Or, if you want to make a copy, you can use a cleaner inject thusly:

flatter_h = h.inject({ }) { |x, (k,v)| x[k] = v[0]; x }

Or, if you have each_with_object available (i.e. Rails or Ruby 1.9):

flatter_h = h.each_with_object({ }) { |(k,v), x| x[k] = v[0] }


Perhaps a somewhat more attractive use of inject. Hash#merge is your friend:

hash = {"k1"=>["v1"], "k2"=>["v2"], "k3"=>["v3"], "k4"=>["v4"]}
hash.inject({}) {|r,a| r.merge(a.first=>a.last.first)}


>> h = {"k1"=>["v1"], "k2"=>["v2"], "k3"=>["v3"], "k4"=>["v4"]}
>> Hash[h.map { |k, vs| [k, vs.first] }]
=> {"k1"=>"v1", "k2"=>"v2", "k3"=>"v3", "k4"=>"v4"}


Combining the Hash[h.map { |k, v| [k, v.first] }] syntax from @tokland's answer with the array destructuring syntax introduced in @mu's h.inject({ }) { |x, (k,v)| x[k] = v[0]; x }, I came up with what I think is the cleanest solution:

h1 = {"k1"=>["v1"], "k2"=>["v2"], "k3"=>["v3"], "k4"=>["v4"]}
h2 = Hash[h1.map{|k,(v)| [k, v]}]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜