0

2 つの大きな CSV ファイルがあります。1 つのファイルは単なるレコードのリストです。もう一方のファイルはレコードのリストですが、最初の列は他のファイルで変更するレコードの行番号です。行全体を置き換えるわけではありません。ヘッダーが一致する行の値を置き換えるだけです。

例えば:

ファイル 1:

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

ファイル 2:

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

目標は、次のような 1 つのファイルになることです。

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

ただし、データはそれよりもはるかに複雑で、CSV に改行が含まれている場合もあります。したがって、行番号に頼ることはできず、代わりにレコード数に頼らなければなりません。(もちろん、改行と改行を置き換えるために両方のファイルを前処理しない限り..これは可能だと思いますが、あまり面白くありません。)

私が抱えている問題は、両方のファイルをループして、ファイル全体のいずれかをメモリにロードせずに適切な置換を行うにはどうすればよいかということです。100MB 以上のファイルをメモリにロードするのは良くないと思いますよね?

また、結果ファイルのレコードは、完了時に同じ順序になっている必要があります。

4

2 に答える 2

1

2 つの列挙子が必要になりますが、これらはネストされていないため、1 つが Enumerator#next を使用する必要があります。つまり、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
于 2012-12-28T11:59:32.867 に答える
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

†は( に基づくのではなく) に基づくインデックスをfile2持っているため、と のカウンターをから開始する必要があります。10index1index21


††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

于 2012-12-28T10:07:23.877 に答える