Разбор CSV файла. Разделение на большее количество файлов

В настоящее время я работаю над небольшим приложением, которое позволит кому-то вводить строки, которые будут разделять больший файл на более мелкие файлы.

У меня возникла проблема с тем, чтобы файл был разделен на более новые файлы. Это мой код для моего метода CSV:

require 'csv'

new_list = []
old_list = []

def import_csv(file)
 puts "Method begins"
 CSV.foreach("public_schools_list.csv", :encoding => 'windows-1251:utf-8', :headers => true) do |row|
 if row["company"].downcase.include?("academy" || "lutheran" || "jewish" || "private" || "christian")
 CSV.open("new_list.csv", "ab") do |n|
 n << row

 puts "First Row"

 new_list << n
 end
 else
 CSV.open("old_list.csv", "ab") do |o|
 o << row

 puts "Second Row"

 old_list << o
 end
 end
 end
end

puts "New Csv: #{new_list.count}"
puts "Old Csv: #{old_list.count}"

Я просто пытаюсь проверить этот код, чтобы увидеть, разделяет ли он файлы. Я не уверен, что некоторые из них верны. В настоящее время в списке CSV есть только четыре элемента. Я использую метод count чтобы проверить, попадают ли они в правильные файлы.

Какой код мне не хватает, чтобы разделить главный файл на два?

вот мой контроллер:

include CSVUpload

def import
 csv_separate(params[:file].tempfile)
 redirect_to root_url
end

то вот модуль, который я использую:

require 'csv'
module CSVUpload

 def csv_separate(file)
 new_list_counter = 0
 old_list_counter = 0

 # puts "Method begins"
 CSV.open("new_list.csv", "ab") do |new_list|
 CSV.open("old_list.csv", "ab") do |old_list| 
 CSV.foreach(file, :encoding => 'windows-1251:utf-8', :headers => true) do |row|
 if row["company"][/\b(?:academy|lutheran|jewish|private|christian)\b/i]
 new_list << row

 new_list_counter += 1
 else
 old_list << row

 old_list_counter += 1
 end
 end
 end
 end
 end
 end

а затем вот форма:

<div>
 <h3>Import a CSV File</h3>
 <%= form_tag({action: "import"}, multipart: true) do %>
 <%= file_field_tag("file") %>
 <%= submit_tag "Import CSV" %>
 <% end %>
</div>

Я надеюсь, что это поможет немного. Благодарю!

1 ответ

Не открывайте и закрывайте выходные файлы для каждой прочитанной строки. Это ужасно неэффективно и тратит процессорное время. Откройте их вне цикла CSV.foreach, а затем напишите им условно.

Кроме того, не суммируйте строки файла в памяти, чтобы вы могли их подсчитать. Вместо этого увеличивайте счетчик.

Кроме того, include? не работает таким образом:

include?("academy" || "lutheran" || "jewish" || "private" || "christian")

В документации говорится:

str.include? other_str -> true or false

------------------------------------------------------------------------------

Returns true if str contains the given string orcharacter.

 "hello".include? "lo" #=> true
 "hello".include? "ol" #=> false
 "hello".include? ?h #=> true

Обратите внимание, что для этого требуется один символ или строка. Использование списка or'd строк приводит только к первой строке:

"academy" || "lutheran" || "jewish" || "private" || "christian" # => "academy"

В результате, только "академия" была бы проверена на предмет включения.

Это не проверено, но выглядит достаточно верно:

require 'csv'


def import_csv(file)
 new_list_counter = 0
 old_list_counter = 0

 puts "Method begins"

 CSV.open("new_list.csv", "ab") do |new_list|
 CSV.open("old_list.csv", "ab") do |old_list|

 CSV.foreach("public_schools_list.csv", :encoding => 'windows-1251:utf-8', :headers => true) do |row|

 if row["company"][/\b(?:academy|lutheran|jewish|private|christian)\b/i]
 new_list << row

 puts "First Row"

 new_list_counter += 1

 else
 old_list << row

 puts "Second Row"

 old_list_counter += 1
 end

 end
 end

 end

 puts "New CSV: #{ new_list_counter }"
 puts "Old CSV: #{ old_list_counter }"

end

Уведомление /\b(?:academy|lutheran|jewish|private|christian)\b/i. Это проверяет несколько подстрок, которые являются полными словами. \b в regex-ese означает "слово-граница", поэтому каждый из встроенных слов или'd вместе использует | тестируются отдельно. /i означает, что он не учитывает регистр. Чтобы выполнить то же самое, используя include? будет включать цикл за списком слов, который является одним из тех алгоритмов, который растет медленнее и медленнее, когда вы добавляете больше слов для тестирования.

row["company"][/\b(?:academy|lutheran|jewish|private|christian)\b/i] чрезвычайно эффективен по сравнению с этим возможным алгоритмом цикла. Использование шаблонов регулярных выражений не является универсальной панацеей. Использованные неправильные шаблоны регулярных выражений могут фактически замедлить вашу программу, а иногда и резко. Правильно используются, но они могут уменьшить ваш код и в правильной ситуации, когда они написаны правильно, могут значительно улучшить скорость. Итак, проверьте, используя тесты, прежде чем вслепую ввести их в код.

licensed under cc by-sa 3.0 with attribution.