Ruby 的 CSV 哈希数组

Array of Hashes to CSV with Ruby

我正在使用哈希数组创建一个 CSV 订单文件。 CSV 输出中的 name 和 id 需要在每一行都相同,但每个订单的行数取决于订单中的 skus 数量。

有没有简单的方法输出这个订单数组?

orders = []
orders << { name:"bob", id:123, sku:[ "123a", "456b", "xyz1" ], qty:[ 2, 4, 1 ] }
orders << { name:"kat", id:987, sku:[ "456b", "aaa0", "xyz1" ], qty:[ 8, 9, 5 ] }
orders << { name:"kat", id:222, sku:[ "123a" ], qty:[ 4 ] }

像这样的 CSV 文件:

name,id,sku,qty
bob,123,123a,2
bob,123,456b,4
bob,123,xyz1,1
kat,987,456b,8
kat,987,aaa0,9
kat,987,xyz1,5
kat,222,123a,4

首先,让我们准备要转储为 CSV 的数组:

asarray = orders.map { |e| 
  [e[:name], e[:id], e[:sku].zip(e[:qty])] 
}.map { |e| 
  e.last.map { |sq| [*e[0..1], *sq] } 
}

现在我们准备好将原始数组序列化为 CSV:

require 'csv'
CSV.open("path/to/file.csv", "wb") do |csv|
  csv << ["name", "id", "sku", "qty"]
  asarray.each { |order|
    order.each { |row|
      csv << row
    }
  }
end

试试这个:

module SKUSeparator
  def map_by_skus
    inject([]) do |csv, order|
      order[:sku].each_with_index do |sku, index|
        csv << [order[:name], order[:id], order[:sku][index], order[:qty][index]]
      end
      csv
    end
  end

  def to_csv
    map_by_skus.map { |line| line.join(",") }.join("\n")
  end
end

ORDERS = [
  {:name=>"bob", :id=>123, :sku=>["123a", "456b", "xyz1"], :qty=>[2, 4, 1]},
  {:name=>"kat", :id=>987, :sku=>["456b", "aaa0", "xyz1"], :qty=>[8, 9, 5]},
  {:name=>"kat", :id=>222, :sku=>["123a"], :qty=>[4]}
]

ORDERS.extend(SKUSeparator).map_by_skus # =>

# [
#   ["bob", 123, "123a", 2],
#   ["bob", 123, "456b", 4],
#   ["bob", 123, "xyz1", 1],
#   ["kat", 987, "456b", 8],
#   ["kat", 987, "aaa0", 9],
#   ["kat", 987, "xyz1", 5],
#   ["kat", 222, "123a", 4]
# ]

ORDERS.extend(SKUSeparator).to_csv # =>

# bob,123,123a,2
# bob,123,456b,4
# bob,123,xyz1,1
# kat,987,456b,8
# kat,987,aaa0,9
# kat,987,xyz1,5
# kat,222,123a,4

作为变体:

orders = []
orders << { name:"bob", id:123, sku:[ "123a", "456b", "xyz1" ], qty:[ 2, 4, 1 ] }
orders << { name:"kat", id:987, sku:[ "456b", "aaa0", "xyz1" ], qty:[ 8, 9, 5 ] }
orders << { name:"kat", id:222, sku:[ "123a" ], qty:[ 4 ] }

csv = ''
orders.each do |el|
  el[:qty].length.times do |idx|
    csv += "#{el[:name]},#{el[:id]},#{el[:sku][idx]},#{el[:qty][idx]}\n"
  end
end
puts csv

结果:

#> bob,123,123a,2
#> bob,123,456b,4
#> bob,123,xyz1,1
#> kat,987,456b,8
#> kat,987,aaa0,9
#> kat,987,xyz1,5
#> kat,222,123a,4