ruby - 将动态数据列附加到多个 CSV
问题描述
我有一个脚本可以下载多个名称相似的 CSV(即 data.csv、data(1).csv),我想在每个 CSV 中附加一列,然后将它们组合成一个 CSV。
例如,
data.csv 有 4 个标题(header_1、header_2 等),我想用变量 foobar 添加 header_5。对于 data.csv,foobar 是“鸭子”,因此对于 data.csv 拥有的每一行,header_5 都会有那么多鸭子。
data(1).csv 是一样的,但这次变量 foobar 现在是“狗”。并且该脚本将用许多狗填充 header_5。
在最后一步,这 2 个 CSV 将被合并——保留修改后的数据——成为一个巨大的 CSV。
我一直在考虑这个问题。我对 Ruby 了解不多,这种问题对我来说是新的,所以我希望我能很好地解释它。
我考虑过首先修改 CSV 以获得新的数据列,然后将它们组合起来,但我一直遇到 CSV 名称的问题。为了让我修改文件,我需要知道名称,所以我想到了通配符。但是,我将如何区分 CSV?它可能会覆盖数据。
我当前的代码有这个问题。
def CSV_Creation (source)
input_files = Dir.glob("data*.csv")
all_headers = input_files.reduce([]) do |all_headers, file|
header_line = File.open(file, &:gets)
all_headers | CSV.parse_line(header_line)
end
CSV.open("out.csv", "a+") do |out|
all_headers << "Source"
out << all_headers
input_files.each do |file|
CSV.foreach(file, headers: true) do |row|
out << all_headers.map { |header| row[header] }
end
end
end
end
- 源参数根据正在下载的 CSV 进行更改
- 我使用通配符收集所有 CSV,收集标题以添加另一个标题,并将所有数据转储到新的 CSV 中。但是当然数据会被覆盖。
我不完全确定如何使最后一列中的数据不被覆盖。
编辑
感谢您迄今为止的所有回复。我已经更新了希望更有意义的代码:
def CSV_Creation (source)
l_source = {'lead_source' => "#{source}"}
input_file = Dir.glob("data*.csv").last
puts "Here is " + input_file
rows = CSV.open(input_file, headers: true).map{ |row| row.to_h }
rows.each { |h| h.merge!(l_source)}
headers = rows.first.keys
rows.first.keys.each {|k| puts k}
csv_response = CSV.generate do |csv|
csv << headers
rows.each do |row|
csv << row.values_at(*headers)
end
end
File.open("#{source}.csv", "w") {|file| file.write(csv_response)}
end
这将创建两个不同的 csv 文件,其中包含适当的列和数据。现在我只需要弄清楚如何组合这两个文件。
第二次编辑
这就是最终代码的样子。它按照我的要求做,所以我认为没关系?
def CSV_Creation (source)
l_source = {'lead_source' => "#{source}"}
input_file = Dir.glob("data*.csv").last
puts "Here is " + input_file
rows = CSV.open(input_file, headers: true).map{ |row| row.to_h }
rows.each { |h| h.merge!(l_source)}
headers = rows.first.keys
rows.first.keys.each {|k| puts k}
csv_response = CSV.generate do |csv|
csv << headers
rows.each do |row|
csv << row.values_at(*headers)
end
end
File.open("#{source}.csv", "w") {|file| file.write(csv_response)}
input_files = Dir.glob("#{source}*.csv")
all_headers = input_files.reduce([]) do |all_headers, file|
header_line = File.open(file, &:gets)
all_headers | CSV.parse_line(header_line)
end
CSV.open("out.csv", "a+") do |out|
out << all_headers
input_files.each do |file|
CSV.foreach(file, headers: true) do |row|
out << all_headers.map { |header| row[header] }
end
end
end
end
非常感谢所有给我建议的人!!
解决方案
我有一个愚蠢的方式来做你问的事情:
- 在 out.csv 文件中加入每个 csv 文件的行(有一点安全性)
- 告诉 source.csv 中哪个列来自文件
# idk what to do with source
def CSV_Creation (source)
input_files = Dir.glob("data*.csv").map { |filename| File.open(filename) }
headers = input_files.map(&:gets)
# Fix for "empty" lines in data files
line_fix = headers.map { |header| CSV.parse_line(header).map { ',' }.join }
CSV.open("out.csv", "a+") do |out|
# We add the header
out.puts headers.map(&:chomp).join(',')
# We try to read all the lines
until (lines = input_files.map(&:gets)).concat.empty?
out.puts lines.map.with_index do |line, index|
line&.chomp || line_fix[index]
end.join(',')
end
end
# In order to know the names we'll store a csv associating header to the filename
File.open('source.csv', 'w') do |f|
f.puts headers.map(&:chomp).join(',')
line = input_files.map.with_index do |file, index|
([file.path] * line_fix[index].size).to_csv
end
f.puts line.map(&:chomp).join(',')
end
ensure
input_files.each(&:close)
end
推荐阅读
- javascript - 使用 Angular 通用的 ngx-translate 在转换参数化值时遇到问题
- python - numpy 数组到 Pandas 表
- jmeter - 调试采样器不显示正则表达式提取器变量
- snowflake-cloud-data-platform - 排除一段时间内的结果
- spring-boot - 如何在 graphql-spring-boot-autoconfigure 中跳过/禁用 GraphQLExtendedScalarsInitializer
- azure-data-factory - Azure 数据工厂重新启动单个群集
- java - 如何发布列表
在改造的参数中? - task - STM32 FreeRTOS,如何清除任务信号标志
- graphql - 从 .graphql 文件导出多个查询
- javascript - JSDoc @param 作为预定义的常量对象