简体   繁体   中英

Transforming an array of arrays to an array of hashes in Ruby

I'm trying to transform a two dimensional array to an array of hashes. Here is my array:

[[8765, 105191, 2.0, 1582.1], [4321, 62870, 2.0, 603.24], [1234, 62870, 2.0, 500.24]]

I'm trying to transform this to an array of hash values. Something like this:

[{"sales_user_id"=>"8765", "user_id"=>"105191", "month"=>"2", "sum"=>"1582.1"},
{"sales_user_id"=>"4321", "user_id"=>"62870", "month"=>"2", "sum"=>"603.24"},
{"sales_user_id"=>"1234", "user_id"=>"62870", "month"=>"2", "sum"=>"500.24"}]

I'm breaking down each array and assigning a key to the values in the array. I'm still a little new to ruby and I'm not sure where to start.

This is pretty straightforward with Enumerable#zip :

values = [ [ 8765, 105191, 2.0, 1582.1 ],
           [ 4321,  62870, 2.0, 603.24 ],
           [ 1234,  62870, 2.0, 500.24 ] ]
keys = %w[sales_user_id user_id month sum]

p values.map {|arr| keys.zip(arr).to_h }
# => [ { "sales_user_id" => 8765, "user_id" => 105191, "month" => 2.0, "sum" =>  1582.1 },
#      { "sales_user_id" => 4321, "user_id" =>  62870, "month" => 2.0, "sum" =>  603.24 },
#      { "sales_user_id" => 1234, "user_id" =>  62870, "month" => 2.0, "sum" =>  500.24 } ]
arr = [[8765, 105191, 2.0, 1582.1 ],
       [4321, 62870,  2.0,  603.24],
       [1234, 62870,  2.0,  500.24]]

keys = ["sales_user_id", "user_id", "month", "sum"]

First way

[keys].product(arr).map { |a| a.transpose.to_h }
  #=> [{"sales_user_id"=>8765, "user_id"=>105191, "month"=>2.0, "sum"=>1582.1},
  #    {"sales_user_id"=>4321, "user_id"=> 62870, "month"=>2.0, "sum"=>603.24},
  #    {"sales_user_id"=>1234, "user_id"=> 62870, "month"=>2.0, "sum"=>500.24}]

The steps:

enum = [keys].product(arr)
  #=> #<Enumerator:
  #     [
  #      [["sales_user_id", "user_id", "month", "sum"], [8765, 105191, 2.0, 1582.1]],
  #      [["sales_user_id", "user_id", "month", "sum"], [4321, 62870, 2.0, 603.24]],
  #      [["sales_user_id", "user_id", "month", "sum"], [1234, 62870, 2.0, 500.24]]
  #     ]:map> 

a = enum.next
  #=> [["sales_user_id", "user_id", "month", "sum"], [8765, 105191, 2.0, 1582.1]]
c = a.transpose
  #=> [["sales_user_id", 8765], ["user_id", 105191], ["month", 2.0], ["sum", 1582.1]] 
c.to_h
  #=> {"sales_user_id"=>8765, "user_id"=>105191, "month"=>2.0, "sum"=>1582.1} 

a = enum.next
  #=> [["sales_user_id", "user_id", "month", "sum"], [4321, 62870, 2.0, 603.24]] 
c = a.transpose
  #=> [["sales_user_id", 4321], ["user_id", 62870], ["month", 2.0], ["sum", 603.24]] 
c.to_h
  #=> {"sales_user_id"=>4321, "user_id"=>62870, "month"=>2.0, "sum"=>603.24} 

a = enum.next
  #=> [["sales_user_id", "user_id", "month", "sum"], [1234, 62870, 2.0, 500.24]] 
c = a.transpose
  #=> [["sales_user_id", 1234], ["user_id", 62870], ["month", 2.0], ["sum", 500.24]] 
c.to_h
  #=> {"sales_user_id"=>1234, "user_id"=>62870, "month"=>2.0, "sum"=>500.24} 

Second way

arr.map do |a|
  ad = a.dup
  { "sales_user_id"=>ad.shift, "user_id"=>ad.shift, "month"=>ad.shift, "sum"=>ad.shift }
end
  #=> [{"sales_user_id"=>8765, "user_id"=>105191, "month"=>2.0, "sum"=>1582.1},
  #    {"sales_user_id"=>4321, "user_id"=> 62870, "month"=>2.0, "sum"=>603.24},
  #    {"sales_user_id"=>1234, "user_id"=> 62870, "month"=>2.0, "sum"=>500.24}]

Also consider using a Struct if you have a fixed set of values per object. Can be used pretty much as a hash.

User = Struct.new(:sales_user_id, :user_id, :month, :sum)

array = [[8765, 105191, 2.0, 1582.1], [4321, 62870, 2.0, 603.24], [1234, 62870, 2.0, 500.24]]

users = array.map {|values| User.new *values}

p users #=> [#<struct User sales_user_id=8765, user_id=105191, month=2.0, sum=1582.1>, #<struct User sales_user_id=4321, user_id=62870, month=2.0, sum=603.24>, #<struct User sales_user_id=1234, user_id=62870, month=2.0, sum=500.24>]


p users.first.user_id    #=> 105191
p users.first['user_id'] #=> 105191
p users.first[:user_id]  #=> 105191

Here's one way to do it that uses .collect to iterate over the outer array and construct a hash for each inner array:

values = [[8765, 105191, 2.0, 1582.1],
          [4321, 62870, 2.0, 603.24],
          [1234, 62870, 2.0, 500.24]]

result = values.collect do |array|
  {
    "sales_user_id" => array[0].to_s,
    "user_id" => array[1].to_s,
    "month" => array[2].to_i.to_s,
    "sum" => array[3].to_s
  }
end

result :

[{"sales_user_id"=>"8765", "user_id"=>"105191", "month"=>"2", "sum"=>"1582.1"},
 {"sales_user_id"=>"4321", "user_id"=>"62870", "month"=>"2", "sum"=>"603.24"},
 {"sales_user_id"=>"1234", "user_id"=>"62870", "month"=>"2", "sum"=>"500.24"}]

It also uses .to_s and .to_i to coerce the result into the values in the question (like 8765 to "8765" and 2.0 to "2" ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM