【问题标题】:Is it possible to generate a CSV using hashes as rows?是否可以使用哈希作为行来生成 CSV?
【发布时间】:2014-12-17 23:19:11
【问题描述】:

我有一个很大的哈希数组,像这样

# note that the key order isn't consistent
data = [
  {foo: 1, bar: 2, baz: 3},
  {foo: 11, baz: 33, bar: 22}
]

我想把它变成 CSV

foo,bar,baz
1,2,3
11,22,33

我这样做是这样的:

columns = [:foo, :bar, :baz]
csv_string = CSV.generate do |csv|
  csv << columns
  data.each do |d|
    row = []
    columns.each do |column|
      row << d[column]
    end
    csv << row
  end
end

有没有更好的方法来做到这一点?我想做的是......

csv_string = CSV.generate do |csv|
  csv << [:foo, :bar, :baz]
  data.each do |row|
    csv.add_row_hash row
  end
end

【问题讨论】:

  • 为什么你有一个大的哈希数组?您是否有可能跳过该步骤并在源代码处生成 CSV?

标签: ruby csv


【解决方案1】:

经过适当的选项以生成,您可以实现所需的目标。请注意,设置标题后,您可以直接将哈希添加到 CSV。

c = CSV.generate(:headers => [:foo, :bar, :baz], :write_headers => true) do |csv|
  data.each { |row| csv << row }
end

输出:

foo,bar,baz
1,2,3
11,22,33

【讨论】:

  • 天啊,库直接支持的?!我用谷歌搜索并阅读了很多文档。即使是现在,阅读docs for the options to new,也不清楚在将哈希添加为行时是否会智能地使用标题信息。事实上,docs for &lt;&lt; 暗示它根本不能被赋予哈希值!
  • 我同意,文档不是那么清楚。它实际上在CSV::Row documentation
  • CSV#&lt;&lt; 是否与CSV::Row#&lt;&lt; 相同?如果不是,那么这不是记录它...
  • 同意,CSV#&lt;&lt; 文档中缺少它。如果您检查源代码,则该功能很明显。
【解决方案2】:

如果可能缺少键,则需要获取所有可能的键

keys = data.map(&:keys).flatten.uniq

然后使用这些键映射每一行。

csv_string = CSV.generate do |csv|
  csv << keys
  data.each do |row|
    csv << row.values_at(keys)
  end
end

【讨论】:

  • 提问者表示每一行中的键顺序不一样。
  • 我可以对密钥进行排序......但是,是的,这会引入其他问题和漏洞。一方面,我无法控制顺序。此外,如果缺少键,则行为将不正确。所以我必须为标题中的所有键填充nil 值的每一行。并确保没有不在标题中的键(在大多数应用程序中不是问题,但不必这样做会很好)
  • row.values_at 在这里可能有用。
  • @muistooshort values_at 如果哈希没有值确实返回 nil,所以这可能是完美的,谢谢!
  • @JohnBachir row[k] 也是如此,我只是认为values_at 读起来更好,因为它正在讨论对row 进行编码而不是对键进行操作。
【解决方案3】:

我的第一个想法:您的data 可用于将数据插入数据库表中。 如果您将此与 csv-output of a DB-table 结合使用,您将获得另一种解决方案。

例子:

data = [
  {foo: 1, bar: 2, baz: 3},
  {foo: 11, baz: 33, bar: 22},
  {foo: 11, baz: 33, bar: 22, xx: 3}, #additional parameters are no problem
]

#Prepare DB as a helper
require 'sequel'
DB = Sequel.sqlite
DB.extension(:sequel_3_dataset_methods) #define to_csv 
DB.create_table(:tab){
  add_column :foo
  add_column :bar
  add_column :baz
}

DB[:tab].multi_insert(data) #fill table
#output as csv (the gsub is necessary on Windows, maybe not necessary on other OS
puts DB[:tab].to_csv.gsub("\r\n","\n")  

缺点:需要续集

优点:您可以很容易地调整订单:

puts DB[:tab].select(:bar, :baz).to_csv.gsub("\r\n","\n")  

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-07
    • 2021-03-09
    • 2020-11-30
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 2022-07-06
    相关资源
    最近更新 更多