#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
.) Прочитайте заголовки, измените их и передайте все остальное.