如何用Ruby为多个CSV添加动态列并合并为单个CSV?
解决Ruby中批量处理CSV并合并的问题
需求回顾
你需要实现的功能是:
- 处理多个名称相似的CSV文件(如
data.csv、data(1).csv) - 为每个CSV添加指定列(比如
data.csv新增列值为"duck",data(1).csv为"dog") - 将所有修改后的CSV合并为单个文件
问题分析
你最初尝试用通配符获取文件时遇到了数据覆盖问题,之后的版本能生成带对应列的单个CSV,但还缺少合并步骤。最终代码已经完成了需求,下面我们来详细拆解关键逻辑:
最终实现代码
def CSV_Creation (source) l_source = {'lead_source' => "#{source}"} # 获取目标CSV文件(这里取最后一个匹配的data*.csv,可根据需要调整) input_file = Dir.glob("data*.csv").last puts "Here is " + input_file # 读取CSV并转为哈希数组,添加指定列 rows = CSV.open(input_file, headers: true).map{ |row| row.to_h } rows.each { |h| h.merge!(l_source)} # 获取表头并生成新的CSV内容 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 # 保存处理后的单个CSV File.open("#{source}.csv", "w") {|file| file.write(csv_response)} # 合并所有处理后的CSV文件 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 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
关键逻辑解释
1. 单个CSV的列添加处理
Dir.glob("data*.csv").last:匹配所有以data开头的CSV文件,取最后一个(你可以根据实际需求调整匹配规则,比如按文件名排序后选择)row.to_h:将CSV行转为哈希,方便后续合并新列h.merge!(l_source):直接在原有行数据中新增lead_source列,值为传入的source参数(比如"duck"或"dog")CSV.generate:生成新的CSV内容,确保表头和行数据对应,最后保存为以source命名的CSV文件
2. 多CSV合并逻辑
Dir.glob("#{source}*.csv"):获取所有以当前source命名的处理后的CSV文件reduce结合|运算符:收集所有文件的表头并自动去重,确保合并后的CSV包含所有可能的列CSV.open("out.csv", "a+"):以追加模式打开输出文件,先写入合并后的表头,再遍历每个处理后的CSV,将每行数据按表头顺序写入,避免数据错位
注意事项
- 如果
out.csv已经存在,a+模式会在文件末尾追加内容。如果需要每次生成新的合并文件,可以改为w模式(会覆盖原有文件) - 若你的CSV文件数量较多或体积较大,建议优化内存使用(比如逐行处理而不是一次性读取所有行)
内容的提问来源于stack exchange,提问作者user7277590
相关产品推荐
相关产品推荐

