2013-03-04 2 views
1

У меня есть около 50 файлов CSV, которые необходимо объединить горизонтально в один CSV.Как мне объединить несколько CSV-файлов по горизонтали?

Заголовки могут игнорироваться. Немного упростил файлы выглядеть следующим образом:

Файл 1:

1,2,4,5,6 
4,5,68,7,4,2 
1,2 

1,2,3 

Файл 2:

1,2,4 
4,5,6,4 
3,4,5 
3,4,5 

Вывод должен выглядеть следующим образом:

1,2,4,5,6,1,2,4 
4,5,68,7,4,2,4,5,6,4 
1,2,3,4,5 
3,4,5 
1,2,3 

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

#!/usr/bin/env ruby 
require 'csv' 
data = Array.new 
filecount=1 
linecount=1 

CSV.open("output.csv", "wb") do |output| 
    Dir.glob('*.csv').each do |each| 
    next if each == 'output.csv' 
    file = CSV.read(each) 
    file.each do |line| 
     data[filecount][linecount] = line 
     linecount=linecount+1 
    end 
    filecount=filecount+1 
    end 
end 

puts data 
+0

Хм, я должен упомянуть, что файлы очень большие. Я написал сценарий bash, который выполняет эту работу, но он очень медленный. Поскольку на сервере имеется около 64 ГБ ОЗУ, должно быть возможно загрузить весь файл в память. – user2132453

+0

Я думаю, что вы на правильном пути со своей идеей цикла. Почему бы вам не попробовать, а затем вернуться сюда с вашими результатами. –

+0

OK Я добавил свою идею. Я не могу получить строки в массиве массивов, это моя проблема. – user2132453

ответ

2

Я подготовил небольшой скрипт, который решает вашу проблему, и добавил некоторые комментарии для лучшего объяснения.

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

#!/usr/bin/env ruby 
require 'csv' 

# map "treats" each element of the array with the block 
files = Dir.glob('csv/*.csv').map { |file| CSV.open file, 'r' } 

CSV.open("output.csv", "wb") do |out| 
    loop do 
     # shift returns the next line 
     # compact remove nil entries 
     line = files.map { |file| file.shift }.compact 
     # remove entry if file has no row 
     line.reject! { |e| e.empty? } 
     # break the endless loop if no input to handle 
     break if line.empty? 
     out << line.flatten 
    end 
end 
+0

Большое спасибо. Я постараюсь полностью понять код. Позже я попытаюсь улучшить его для своих нужд. – user2132453

Смежные вопросы