【问题标题】:Ruby - Convert Nested Hash to CSV [closed]Ruby - 将嵌套哈希转换为 CSV [关闭]
【发布时间】:2020-12-22 00:22:21
【问题描述】:

我目前有一个具有以下结构的对象(failure_object):

{"2020-08-25"=>{"adwords"=>8, "analytics"=>69, "bing"=>5, "dfa"=>3, "doubleclick"=>2, " getstat"=>2}, "2020-08-26"=>{"adwords"=>22, "bing"=>7, "dfa"=>4, "doubleclick"=>6, "getstat"=> 2},...

我希望将其写入包含以下列的 CSV:

+------------+--------------+-------------+
|一个 |乙| C |
+------------+--------------+-------------+
| 2020-08-25 |广告词 | 8 |
| 2020-08-25 |分析 | 69 |
| 2020-08-25 |冰 | 5 |
| 2020-08-25 | dfa | 3 |
| 2020-08-25 |双击 | 2 |
| 2020-08-25 |获取统计信息 | 2 |
| 2020-08-26 |广告词 | 22 |
| 2020-08-26 |冰 | 7 |
| 2020-08-26 | dfa | 4 |
| 2020-08-26 |双击 | 6 |
| 2020-08-26 |获取统计信息 | 2 |
+---+--------+-------------+-------------+

到目前为止,我编写 ruby​​ 并输出到 csv 的经验只涵盖了数组,a 虽然我可以将此哈希对象转换为数组,但键值对之间的关​​系并未以我想要的方式保留。

任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 如果+---+--------+--------------+-------------+ 行不被写入CSV 文件,您应该删除它们。如果字段分隔符是管道 (|),则应写为 2020-08-25|adwords|8 而不是 | 2020-08-25 | adwords | 8 |。为避免混淆,您需要显示 CSV 文件的准确图像。此外,让您散列一个完整的 Ruby 对象,该对象对应于您显示的文件的图像(即,没有 ...)。这是针对您可能提出的任何问题的一般建议。
  • 为每个输入分配一个变量(例如,h = { "2020-08-25"=>{...})也很有帮助,这样读者就可以在答案和 cmets 中引用该变量(在我的示例中为 h),而无需定义它.
  • @max :您显示的所需输出不是有效的 CSV 文件。除此之外,将问题分为两个步骤:(1)将您的哈希转换为字符串数组的数组,保存您需要在结果文件中显示的数据,(2)将此数组转换为 CSV(或您需要的任何格式)。如果您在其中一个步骤中遇到困难,请针对该子问题提出一个单独的问题。

标签: ruby csv hash


【解决方案1】:
data = {
  "2020-08-25"=>{ "adwords"=>8, "analytics"=>69, "bing"=>5, "dfa"=>3,
                  "doubleclick"=>2, "getstat"=>2 },
  "2020-08-26"=>{ "adwords"=>22, "bing"=>7, "dfa"=>4, "doubleclick"=>6,
                  "getstat"=>2 }
}

从 CSV 对象以外的对象写入 CSV 文件时(例如,在读取要更改的 CSV 文件时获得),使用 CSV 方法没有特别的优势。这里我们可以写如下。

COL_SEP = '|'
fname = 'tmp.csv'

File.open(fname, 'w') do |f|
  f.puts 'A|B|C'
  data.each { |date,h| h.each { |k,v| f.puts [date,k,v].join(COL_SEP) } }
end

让我们检查一下:

puts File.read(fname)
A|B|C
2020-08-25|adwords|8
2020-08-25|analytics|69
2020-08-25|bing|5
2020-08-25|dfa|3
2020-08-25|doubleclick|2
2020-08-25|getstat|2
2020-08-26|adwords|22
2020-08-26|bing|7
2020-08-26|dfa|4
2020-08-26|doubleclick|6
2020-08-26|getstat|2

File::open。通过将open 与块一起使用,文件在写入后会自动关闭。如果我写了f = File.open(fname, 'w'),我需要(记得)在写完文件后用f.close 关闭文件。

另见IO#puts。应该使用puts 而不是IO#write,因为它添加了一个行终止符。回想一下FileIO (File.superclass #=> IO) 的子类,所以File 继承了IO 的方法。

要使用 CSV 方法创建相同的文件,可以编写以下代码。

require 'csv'

CSV.open(fname, 'w', col_sep: COL_SEP) do |csv|
  csv << ['A', 'B', 'C']
  data.each { |date,h| h.each { |k,v| csv << [date,k,v] } }
end
  #=> <as above>

如您所见,使用 CSV 方法几乎没有什么不同。见CSV::open

【讨论】:

    猜你喜欢
    • 2016-09-14
    • 1970-01-01
    • 2019-08-01
    • 2015-08-12
    • 2013-11-13
    • 1970-01-01
    • 2017-06-09
    • 1970-01-01
    • 2016-10-31
    相关资源
    最近更新 更多