Reputation: 27
Supposing I have an array that looks like:
[
[["str1"],["val1"],["val2"]],
[["str2"], ["val1"], ["val2"], ["val3"]]
]
Is there a way for me to get a Hash that looks like:
{
"str1" => [["val1"],["val2"]],
"str2" => [["val1"],["val2"],["val3"]]
}
Upvotes: 1
Views: 3143
Reputation: 110685
arr = [
[["str1"],["val1"],["val2"]],
[["str2"], ["val1"], ["val2"], ["val3"]]
]
arr.each_with_object({}) { |((k), *values), h| h[k]=values }
#=> {"str1"=>[["val1"], ["val2"]], "str2"=>[["val1"], ["val2"], ["val3"]]}
This illustrates how Ruby's use of parallel assignment for determining the values of block variables can be used to advantage.
Upvotes: 0
Reputation: 110685
If your array is arr
, you could write the following.
Marshal.load(Marshal.dump(arr)).map { |a| [a.shift.first, a.map(&:first)] }.to_h
#=> {"str1"=>["val1", "val2"],
# "str2"=>["val1", "val2", "val3"]}
A slight variation would be:
Marshal.load(Marshal.dump(arr)).map { |a| [a.shift.first, a] }.to_h
#=> {"str1"=>["val1", "val2"],
# "str2"=>["val1", "val2", "val3"]}
Note: We're using the Marshal class to make an exact copy of arr
to avoid modifying the original array. Object#dup or Object#clone won't work here.
Upvotes: 2
Reputation: 52357
a.map { |a| [a.first.first, a.drop(1)] }.to_h
# or
a.each_with_object({}) {|a, h| h[a.first.first] = a.drop(1) }
#=> {
# "str1"=>[["val1"], ["val2"]],
# "str2"=>[["val1"], ["val2"], ["val3"]]
# }
If you do not want to have each element in a separate array:
Hash[a.map(&:flatten).map { |a| [a.first, a.drop(1)] }]
#=> {"str1"=>["val1", "val2"], "str2"=>["val1", "val2", "val3"]}
Upvotes: 4