2012-12-28 150 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 

相關問題