首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将动态数据列追加到多个CSV

将动态数据列追加到多个CSV
EN

Stack Overflow用户
提问于 2019-06-19 20:57:51
回答 2查看 202关注 0票数 0

我有一个下载多个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都会有那么多的鸭子。

数据(1).csv是相同的,但是这个时间变量foobar现在是“狗”。该脚本将在header_5中填充任意数量的狗。

在最后一步,两个CSV将被合并--保留修改后的数据--成为一个巨大的CSV。

我已经想了很长时间了。我对Ruby了解不多,这种问题对我来说是新的,所以我希望我能很好地解释它。

我想过首先修改CSV以获得新的数据列,然后合并它们,但我一直遇到CSV名称的问题。为了让我修改这些文件,我需要知道这些文件的名称,所以我想到了通配符。但是,我如何区分CSV呢?它可能会覆盖数据。

我当前的代码就有这个问题。

代码语言:javascript
复制
 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中。当然,数据也会被覆盖。

我不能完全确定如何防止最后一列中的数据不被覆盖。

编辑

感谢您到目前为止的所有回复。我已经更新了代码,希望这些代码更有意义:

代码语言:javascript
复制
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文件。现在我只需要弄清楚如何组合这两个文件。

第二次编辑

这就是最终代码的样子。它做到了我所要求的,所以我想它是正确的?

代码语言:javascript
复制
 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 

非常感谢给我建议的每一个人!

EN

回答 2

Stack Overflow用户

发布于 2019-06-19 21:43:59

我有个愚蠢的方法可以按你的要求去做:

  • 在out.csv文件中连接每个csv文件的行(有一点安全性)
  • 告诉您source.csv

中的列来自哪个文件

代码语言:javascript
复制
# 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
票数 1
EN

Stack Overflow用户

发布于 2019-06-20 08:34:26

代码

代码语言:javascript
复制
require 'csv'

def combine_csv_files(*csv_files, sep, out_file_name)
  (file_name, new_header_name), *rest = csv_files
  csv = CSV.read(file_name, headers: true, col_sep: sep)
  new_col = (1..csv.size).to_a
  csv[new_header_name] = new_col
  rest.each do |file_name, new_header_name|
    csv1 = CSV.read(file_name, headers: true, col_sep: sep)
    csv1.headers.each { |header| csv1.each { |row| csv[header] = row[header] } }
    csv[new_header_name] = new_col
  end
  CSV.open(out_file_name, "w") do |f|
    f << csv.headers
    csv.each { |row| f << row }
  end
end    

示例

假设我们有文件

代码语言:javascript
复制
FNAME1 = 'dogsandcats.csv'
FNAME2 = 'cowsandpigs.csv'

其内容与我的另一个答案中给出的内容相同,我们希望向这两个文件中分别添加标题为"col1""col2"的列,并将这两个文件组合在一起。

代码语言:javascript
复制
combine_csv_files(*[[FNAME1, "col1"], [FNAME2, "col2"]], ',', 'everything.csv') 

puts IO.read('everything.csv')
dog,cat,col1,cow,pig,col2
woof,purr,1,moo,oink,1
devoted,independent,2,dumb,smart,2

说明

步骤如下(对于示例中定义的FNAME1FNAME2 )。

代码语言:javascript
复制
csv_files = [[FNAME1, "col1"], [FNAME2, "col2"]]
sep = ','
out_file_name = 'everything.csv'

在第一个元素和所有剩余元素之间拆分csv_files

代码语言:javascript
复制
(file_name, new_header_name), *rest = csv_files
  #=> [["dogsandcats.csv", "col1"], ["cowsandpigs.csv", "col2"]]
file_name
  #=> "dogsandcats.csv"
new_header_name
  #=> "col1"
rest
  #=> [["cowsandpigs.csv", "col2"]]

以这种方式划分csv_files的过程称为array decomposition。现在读取第一个文件,创建一个CSV对象。

代码语言:javascript
复制
csv = CSV.read(file_name, headers: true, col_sep: sep)
  #=> #<CSV::Table mode:col_or_row row_count:3>

让我们看看我们有什么。

代码语言:javascript
复制
csv.to_a
  #=> [["dog", "cat"], ["woof", "purr"], ["devoted", "independent"]]

现在添加一列,看看我们现在有什么。

代码语言:javascript
复制
new_col = (1..csv.size).to_a 
csv[new_header_name] = new_col
  #=> [1, 2] 
csv.to_a
  #=> [["dog", "cat", "col1"], ["woof", "purr", 1], ["devoted", "independent", 2]]

读取下一个CSV文件的描述符,然后将该文件读取到CSV对象csv1

代码语言:javascript
复制
file_name, new_header_name = rest.shift
  #=> ["cowsandpigs.csv", "col2"] 
csv1 = CSV.read(file_name, headers: true, col_sep: sep)
  #=> #<CSV::Table mode:col_or_row row_count:3>
csv1.to_a
  #=> [["cow", "pig"], ["moo", "oink"], ["dumb", "smart"]]

csv1追加到csv

代码语言:javascript
复制
csv1.headers.each { |header| csv[header] = csv1.map { |row| row[header] } }
  #=> ["cow", "pig"]
csv.to_a
  #=> [["dog",     "cat",         "col1", "cow",  "pig"  ],
  #    ["woof",    "purr",        1,      "moo",  "oink" ],
  #    ["devoted", "independent", 2,      "dumb", "smart"]] 

添加新列并检查csv

代码语言:javascript
复制
csv[new_header_name] = new_col
  #=> [1, 2]
csv.to_a
  #=> [["dog",     "cat",         "col1", "cow",  "pig",   "col2"],
  #    ["woof",    "purr",        1,      "moo",  "oink",  1     ],
  #    ["devoted", "independent", 2,      "dumb", "smart", 2     ]]

剩下的工作就是将csv写到文件中。

代码语言:javascript
复制
CSV.open(out_file_name, "w") do |f|
  f << csv.headers
  csv.each { |row| f << row }
end
  #> #<CSV::Table mode:col_or_row row_count:3>

让我们看一下刚刚写入的文件的内容:

代码语言:javascript
复制
puts IO.read(out_file_name)
dog,cat,col1,cow,pig,col2
woof,purr,1,moo,oink,1
devoted,independent,2,dumb,smart,2
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56668220

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档