Создать новый CSV, объединяющий два CSV-файла - PullRequest
0 голосов
/ 08 февраля 2019

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

%w{ Name E-mail Job Phone Application_date } 

у другого есть

%w{ E-mail Note }

То, что я хочу, это объединить два в уникальный CSV..с этим заголовком

%w { Name E-mail Job Phone Application_date Note }

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

require 'csv'

desc "Import csv candidates into the database"

task candidates: :environment do
  filepath_candidates_csv = 'data/Import task - Candidates.csv'
  filepath_note_csv = 'data/Import task - Notes.csv'
  filepath_final_csv = 'data/Final.csv'

  #removing candidates duplicates from the csv
  candidates = CSV.read(filepath_candidates_csv)
  new_candidates = candidates.uniq {|x| x.first}

  # removing candidates notes from the csv
  notes = CSV.read(filepath_note_csv)
  new_notes = notes.uniq {|x| x.first}
  new_notes[0][0] = "E-mail"

  # generate new csv array with the updated fields
  hs = %w{ Name E-mail Phone Job Created_at Note }
  CSV.open(filepath_final_csv, "wb") do |csv|
    csv << hs
    CSV.parse_line(new_candidates) do |line|
      csv << line unless line.contain?("E-mail")
    end
  end
end

я получаю эту ошибку

Running via Spring preloader in process 9372
rake aborted!
NoMethodError: private method `gets' called for #<Array:0x00005638b5452bc8>
/home/luis/code/levisn1/Import-Task/csv_Importer/lib/tasks/import.rake:23:in `block (2 levels) in <main>'
/home/luis/code/levisn1/Import-Task/csv_Importer/lib/tasks/import.rake:21:in `block in <main>'
-e:1:in `<main>'
Tasks: TOP => candidates
(See full trace by running task with --trace)

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Это наивная реализация.Вы можете улучшить его.

Так же, как идея для вас.

Вот пример csv-файлов:

$ cat first.csv
name,email,phone,job,created_at
John,john@john.us,112,police,21.02.
Jack,jack@jack.us,112,ambulance,22.02.
Ivan,ivan@ivan.ru,02,kgb,23.02.

$ cat second.csv
email,note
ivan@ivan.ru,some note

Наивный сценарий:

require 'csv'

first_csv = CSV.
              read('first.csv', headers: true).
              map { |value| { name:       value['name'],
                              email:      value['email'],
                              phone:      value['phone'],
                              job:        value['job'],
                              created_at: value['created_at'] } }

second_csv = CSV.
               read('second.csv', headers: true).
               map { |value| { email: value['email'],
                               note:  value['note'] } }

# The same email searching

first_csv.each do |f|
  second_csv.each do |s|
    f.merge! s if f[:email] == s[:email]
  end
end

# Write to new CSV

CSV.open('new.csv', 'w') do |csv|
  csv << %w(name email phone job created_at note)
  first_csv.each do |info|
    csv << info.values_at(:name, :email, :phone, :job, :created_at, :note)
  end
end

Проверка

$ cat new.csv
name,email,phone,job,created_at,note
John,john@john.us,112,police,21.02.,
Jack,jack@jack.us,112,ambulance,22.02.,
Ivan,ivan@ivan.ru,02,kgb,23.02.,some note
0 голосов
/ 08 февраля 2019

Сначала вам нужно проанализировать оба файла - вы можете сохранить каждую строку в хэше или создать новый класс и сохранить экземпляры этого класса.Во-вторых, вам нужно связать записи с одним и тем же адресом электронной почты (если вы создаете экземпляры своего собственного класса, вы можете назначить заметки нужному экземпляру при разборе второго csv) Наконец, вы хотите снова написать файл csv.

Посмотрите на этот камень - он может быть полезен https://github.com/ruby/csv

Как это звучит?

РЕДАКТИРОВАТЬ: вот код, если вы используете класс для решения проблемы

class Person
  attr_reader :name, :email, :phone, :job, :created_at, :note
  attr_writer :note
  #state
  # name,email,phone,job,created_at
  def initialize(name, email, phone, job, created_at, note)
    @name = name
    @email = email
    @phone = phone
    @job = job
    @created_at = created_at
    @note = note
  end
  #behaviour
end

#little test:
person_1 = Person.new("john", "john@john.us", "112", "police", "21.02.", nil)
p person_1

require 'csv'
csv_options = { headers: :first_row }
filepath    = 'persons.csv'
persons = []

CSV.foreach(filepath, csv_options) do |row|
  persons << Person.new(row["name"], row["email"], row["phone"], row["job"], row["created_at"], nil)
end

filepath_2 = "notes.csv"
CSV.foreach(filepath_2, csv_options) do |row|
  persons.each do |person|
    if person.email == row["email"]
      person.note = row["note"]
    end
  end
end

p persons

csv_options = { col_sep: ',', force_quotes: true, quote_char: '"' }
filepath    = 'combined.csv'

CSV.open(filepath, 'wb', csv_options) do |csv|
  csv << ['name', 'email', 'phone', 'job', 'created_at', "note"]
  persons.each do |person|
    csv << [person.name, person.email, person.phone, person.job, person.created_at, person.note]
  end
end

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...