как мне сопоставить один CSV-файл с другим с помощью ruby

#ruby #csv

#рубин #csv — файл #ruby #csv

Вопрос:

У меня есть два CSV-файла с разными заголовками.

допустим, csv 1 имеет заголовки один, два, три, четыре, и я хочу создать csv с заголовками пять, шесть, семь, восемь.

Мне трудно написать код для открытия первого CSV-файла, а затем создать второй CSV-файл.

Вот текущий код, который у меня есть.

 require 'csv'

wmj_headers = [
  "Project Number", 
  "Task ID",    
  "Task Name",
  "Status Comment", 
  "Act Complete", 
  "Plan Complete", 
  "Description"]

jir_headers_hash = {
  "Summary" => "Task Name",
  "Issue key" => "Status Comment",
  "Resolved" => "Act Complete",
  "Due date" => "Plan Complete",
  "Description" => "Description"
}
puts "Enter path to a directory of .csv files"
dir_path = gets.chomp
csv_file_names = Dir["#{dir_path}*.csv"]

csv_file_names.each do |f_path|
  base_name = File.basename(f_path, '.csv')
  wmj_name = "#{base_name}_wmj.csv"

  arr = []
  mycount = 0
  CSV.open(wmj_name, "wb") do |row| 
    row << wmj_headers 


    CSV.foreach(f_path, :headers => true) do |r|
      r.headers.each do |value|
        if jir_headers_hash[value].nil? == false
          arr << r[value]
        end
      end
    end 
    row << arr
  end
end
  

Ответ №1:

Люди склонны все усложнять. Вам вообще не нужна какая-либо обработка CSV для замены заголовков.

 $ cat /tmp/src.csv
one,two,three
1,2,3
4,5,6
  

Давайте заменим заголовки и передадим все остальное нетронутым.

 subst = {"one" => "ONE", "two" => "TWO", "three" => "THREE"}
src, dest = %w[/tmp/src.csv /tmp/dest.csv].map { |f| File.new f, "a " }
headers = src.readline() # read just headers
dest.write(headers.gsub(/b(#{Regexp.union(subst.keys)})b/, )) # write headers
IO.copy_stream(src, dest, -1, headers.length) # stream the rest
[src, dest].each(amp;:close)
  

Проверьте это:

 $ cat /tmp/dest.csv
ONE,TWO,THREE
1,2,3
4,5,6
  

Ответ №2:

Если вы хотите заменить имена столбцов CSV, вот это:

 require 'csv'

# [["one", "two", "three"], ["1", "2", "3"], ["4", "5", "6"]]
csv = CSV.read('data.csv')

# new keys
ks = ['k1', 'k2', 'k3']

# [["k1", "k2", "k3"], ["1", "2", "3"], ["4", "5", "6"]]
k = csv.transpose.each_with_index.map do |x,i|
  x[0] = ks[i]
  x
end.transpose

# write new file
CSV.open("myfile.csv", "w") do |csv|
  k.each do |row|
    csv << row
  end
end
  

Комментарии:

1. Этот код загружает весь CSV-файл в память, что неприемлемо во многих вариантах использования. Никогда не следует загружать весь файл целиком, пока возможна потоковая передача.

2. @AlekseiMatiushkin вы правы, ваше решение лучше.

3. Это также может быть достигнуто с помощью CSV , вам просто не нужно загружать весь файл в память (тем не менее, избавьтесь от transpose .) Прочитайте заголовки, измените их и передайте все остальное.