Объединять CSV-файлы в общем поле с ruby ​​/fastcsv

У меня есть "главный" файл с несколькими столбцами: 1 2 3 4 5. У меня есть несколько других файлов с меньшим количеством строк, чем основной файл, каждый из которых содержит столбцы: 1 6. Я хочу объединить эти файлы, соответствующие в поле столбца 1 и добавьте столбец 6 к мастеру. Я видел некоторые решения на python/UNIX, но предпочел бы использовать ruby ​​/fastcsv, если это хорошо подходит. Буду признателен за любую помощь в начале работы.

3 ответа

Решение

FasterCSV - теперь стандартная реализация CSV в Ruby 1.9. Этот код не проверен, но должен работать.

require 'csv'
master = CSV.read('master.csv') # Reads in master
master.each {|each| each.push('')} # Adds another column to all rows
Dir.glob('*.csv').each do |each| #Goes thru all csv files
  next if each == 'master.csv' # skips the master csv file
  file = CSV.read(each) # Reads in each one
  file.each do |line| #Goes thru each line of the file
    temp = master.assoc(line[0]) # Finds the appropriate line in master
    temp[-1] = line[1] if temp #updates last column if line is found
  end
end

csv = CSV.open('output.csv','wb') #opens output csv file for writing
master.each {|each| csv << each} #Goes thru modified master and saves it to file
$ cat j4.csv
how, now, brown, cow, f1
now, is, the, time, f2
one, two, three, four, five
xhow, now, brown, cow, f1
xnow, is, the, time, f2
xone, two, three, four, five
$ cat j4a.csv
how, b
one, d
$ cat hj.rb
require 'pp'
require 'rubygems'
require 'fastercsv'

pp(
  FasterCSV.read('j4a.csv').inject(
    FasterCSV.read('j4.csv').inject({}) do |m, e|
      m[e[0]] = e
      m
    end) do |m, e|
    k = e[0]
    m[k] << e.last if m[k]
    m
  end.values)
$ ruby hj.rb
[["now", " is", " the", " time", " f2"],
 ["xhow", " now", " brown", " cow", " f1"],
 ["xone", " two", " three", " four", " five"],
 ["how", " now", " brown", " cow", " f1", " b"],
 ["one", " two", " three", " four", " five", " d"],
 ["xnow", " is", " the", " time", " f2"]]

Это работает, отображая ваш главный файл в хэш с ключом один столбец, а затем он просто ищет ключ из других ваших файлов. Как написано, код добавляет последний столбец, когда ключи совпадают. Поскольку у вас есть несколько неосновных файлов, вы можете адаптировать концепцию, заменив FasterCSV.read('j4a.csv') с помощью метода, который читает каждый файл и объединяет их все в один массив массивов, или вы можете просто сохранить результат из внутреннего inject (главный хэш) и примените каждый файл к нему в цикле.

temp = master.assoc(line[0]) 

Выше очень медленный процесс. Весь комплекс по крайней мере O(n^2).

Я бы использовал следующий процесс:

  1. для 1 6 csv преобразуйте его в большой хеш с 1 в качестве ключа и 6 в качестве значения, названного 1_to_6_hash
  2. цикл 1 2 3 4 5 CSV строка за строкой, установите строку [6] = 1_to_6_hash[строка [1]]

Это значительно снизит комплекс до O(n)

Другие вопросы по тегам