2012-12-28 161 views
0

我有两个大型的iscsi CSV文件。一个文件只是一个记录列表。另一个文件是一个记录列表,但第一列是它在另一个文件中修改的记录的行号。它不会取代整个行;它只是替换具有匹配标题的行中的值。使用Ruby将CSV文件中的特定记录替换为另一个CSV文件的记录

例如:

文件1:

"First","Last","Lang" 
"John","Doe","Ruby" 
"Jane","Doe","Perl" 
"Dane","Joe","Lisp" 

文件2:

"Seq","Lang" 
2,"Ruby" 

的目标是用一个文件看起来像这样结束了:

"First","Last","Lang" 
"John","Doe","Ruby" 
"Jane","Doe","Ruby" 
"Dane","Joe","Lisp" 

然而,数据很多比这更复杂,甚至可能在CSV中包含换行符。因此,我不能依赖行号,而必须依靠记录数。 (当然,除非我预处理这两个文件,以取代换行符和回车..我认为这是可能的,但不太有趣。)

我的问题是如何循环浏览两个文件并进行正确的替换将整个文件加载到内存中。我相信100MB +文件加载到内存中是一个坏主意,对吧?

此外,结果文件中的记录应该在相同的顺序时完成。

+0

猜测这些手动编码的CSV文件?我假设是因为你将每个字符串包装在'''中,当你提供的值完全没有必要。 –

+1

是文件2的'Seq'列的顺序吗? – pguardiario

+0

我只是用手输入例子,文件,其中一个不使用引号,除非必要和其他引用。CSV应解析它们,无论是否带引号。 –

回答

1

您将需要2个枚举,但由于他们没有嵌套,一个需要请使用下一个Enumerator#,这意味着您需要小心提起EOF异常:

e = CSV.open('file2.csv', :headers => true).each 
seq = e.next 

output = CSV.open('output.csv', 'w') 

csv = CSV.open('file1.csv') 
csv.each do |row| 
    if seq['Seq'].to_i == csv.lineno - 1 
    row[2] = seq['Lang'] 
    seq = e.next rescue ({'Seq' => -1}) 
    end 
    output << row 
end 
1

这基本上是我怎么会处理它,如果文件过大加载到内存

// pseudocode 

f1 = fopen(file1) 
f2 = fopen(file2) 
f3 = fopen(newfile) 

// loop through exceptions 
foreach row2, index2 of f2 

    // loop through file1 until a matched row is found 
    while (row1, index1 of f1) && (row1 not null) && (row2[seq] <= index1) 

    // patch 
    if row2[seq] == index1 
     row1[lang] = row2[lang] 
    endif 

    // write out to new file 
    f3.write row1 

    endwhile 
endforeach 

†由于您file21基指数(而不是被0基) ,你会想要开始你的index1index2计数器在1


††如果lang是不是你总是会更换色谱柱:

// at the beginning of the foreach loop 
if col is null 
    cols = array_keys row2 
    col = cols[2] // 1-based index 
end 

// the new patch block 
if row2[seq] == index1 
    row1[col] = row2[col] 
endif 

相关问题