IronCode
IronCode

Reputation: 27

Get first element of nested array for hash key

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

Answers (3)

Cary Swoveland
Cary Swoveland

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

Cary Swoveland
Cary Swoveland

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

Andrey Deineko
Andrey Deineko

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

Related Questions