Объедините два CSV-файла в Ruby без использования таблиц - PullRequest
0 голосов
/ 10 октября 2019

У меня есть 2 CSV-файла с такими столбцами, как A, B, C .. & D, E, F. Я хочу объединить эти два CSV-файла в новый файл со строками, где File1.B = File2.E, а в строке будут столбцы A, B/E, C, D, F. Как я могу достичь этого JOIN без использования таблиц?

Ответы [ 2 ]

1 голос
/ 10 октября 2019

Если у вас есть такие CSV-файлы:

first.csv:

A | B | C
1 | 1 | 1
2 | 2 | 2
3 | 4 | 5
6 | 9 | 9

second.csv:

D  | E | F
21 | 1 | 41
22 | 5 | 42
23 | 8 | 45
26 | 9 | 239

Вы можете сделать что-то вроде этого:

require 'csv'

first = CSV.read('first.csv')
second = CSV.read('second.csv')

CSV.open("result.csv", "w") do |csv|
  csv << %w[A B.E C D F]
  first.each do |rowF|
    second.each do |rowS|
      csv << [rowF[0],rowF[1],rowF[2],rowS[0],rowS[2]] if rowF[1] == rowS[1]
    end
  end

end

Чтобы получить это:

result.csv:

A | B.E | C | D  | F
1 | 1   | 1 | 21 | 41
6 | 9   | 9 | 26 | 239
0 голосов
/ 12 октября 2019

Givens

Нам даны следующие данные.

Пути для двух входных файлов:

fname1 = 't1.csv'
fname2 = 't2.csv'

Путь для выводаfile:

fname3 = 't3.csv'

Имена заголовков для сопоставления в каждом из двух входных файлов:

target1 = 'B'
target2 = 'E'

Я предполагаю, что (как в случае с примером) двафайлы обязательно должны содержать одинаковое количество строк.

Создание тестовых файлов

Давайте сначала создадим два файла:

str = [%w|A B C|, %w|1 1 1|, %w|2 2 2|, %w|3 4 5|, %w|6 9 9|].
        map { |a| a.join(",") }.join("\n")
  #=> "A,B,C\n1,1,1\n2,2,2\n3,4,5\n6,9,9"
File.write(fname1, str)
  #=> 29

str = [%w|D E F|, %w|21 1 41|, %w|22 5 42|, %w|23 8 45|, %w|26 9 239|].
        map { |a| a.join(",") }.join("\n")
  #=> "D,E,F\n21,1,41\n22,5,42\n23,8,45\n26,9,239" 
File.write(fname2, str)
  #=> 38

Считать входные файлы в CSV::Table объекты

При чтении fname1 я буду использовать опцию :header_converters для преобразования заголовка "B" до "B/E". Обратите внимание, что для этого не требуется знание местоположения столбца с заголовком "B" (или чем бы то ни было).

require 'csv'

new_target1 = target1 + "/" + target2
  #=> "B/E"

csv1 = CSV.read(fname1, headers: true,
  header_converters: lambda { |header| header==target1 ? new_target1 : header})
csv2 = CSV.read(fname2, headers: true)

Создание массивов заголовков для записи из каждого входного файла

headers1 = csv1.headers
  #=> ["A", "B/E", "C"]
headers2 = csv2.headers - [target2]
  #=> ["D", "F"]

Создание выходного файла

Сначала мы запишем новые заголовки headers1 + headers2 в выходной файл.

Далее,для каждого индекса строки i (i = 0, соответствующего первой строке после строки заголовка в каждом файле), для которого выполняется условие, мы записываем как одну строку элементы csv1[i] и csv2[i], которые являютсяв столбцах, имеющих заголовки в headers1 и headers2. Условие, которое должно быть выполнено для записи строк с индексом i, заключается в том, что i удовлетворяет:

csv1[i][new_target1] == csv2[i][target2] #=> true

Теперь откройте fname3 для записи, запишите заголовки и затем тело. 1068 *

Давайте подтвердим, что написанное верно.

puts File.read(fname3)
A,B/E,C,D,F
1,1,1,21,41
6,9,9,26,239
...