大量のCSVファイルを文字列型のキーで昇順にソート(sort:並べ替え)するスクリプトです。
[2-4-5.大量のCSVファイルのソートする場合の考慮事項]でソート(sort:並べ替え)キーごとの累計件数から割り出したソート(sort:並べ替え)キーをもとに大量のCSVファイルを分割しながら並べ替えていきます。下記の例で"AAJJ"の箇所に分割して並べ替える際の基準になるソート(sort:並べ替え)キーを指定していきます。このとき、「le」や「lt」で比較する場合には、ソート(sort:並べ替え)キーを小さい順に指定し、「ge」や「gt」で比較する場合には、ソート(sort:並べ替え)キーを大きい順に指定します。
if ($in1[0] le "AAJJ") { $sort_record01{$key} = $line1; }
実際に応用する場合は、入出力データのファイル名を変更し、「@sortkey = (0,1)」の部分を変更します。この例では、1番目の項目を第1キーに、2番目の項目を第2キーとして並べ替えるように指定しています。Perlでは、配列のインデックスは「0」から開始されますので、1番目の項目を「0」、2番目の項目を「1」として指定することに注意してください。
下記の例では、フィールドを「"」(ダブルクォーテーションつき)で囲み、それぞれのデータを「,」(カンマ)で区切っている形式を前提としているため、
$tmp = $line1; $tmp =~ s/(?:\x0D\x0A|[\x0D\x0A])?$/,/; @in1 = map {/^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_} ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g);
としていますが、フィールドを「"」(ダブルクォーテーションつき)で囲まずに、それぞれのデータを「,」(カンマ)で区切っている、いわゆる「CSV2形式」であれば、以下のようにすることができます。
@in1 = split(",",$line1,-1);
また、タブ区切りであれば、以下のようにすることができます。
@in1 = split("\t",$line1,-1);
# csvsort_many.pl # 内容 :大量のCSVファイルを文字列型で昇順にソート(並べ替え)する # Copyright (c) 2011 Mitsuo Minagawa, All rights reserved. # (minagawa@fb3.so-net.ne.jp) # 使用方法 : c:\>perl csvsort_many.pl # open(IN1,"input.txt"); open(OUT1,">output.txt"); # ソート(並べ替え)キーの入っている項目番号 @sortkey = (0,1); # ソート(並べ替え)用のキー $key = undef; # ソート(並べ替え)するキーとレコードをセットするハッシュ %sort_record01 = (); %sort_record02 = (); %sort_record03 = (); %sort_record04 = (); %sort_record05 = (); %sort_record06 = (); %sort_record07 = (); %sort_record08 = (); %sort_record09 = (); %sort_record10 = (); %sort_record11 = (); %sort_record12 = (); # 入力件数 $in1_ctr = 0; # ファイル入力 while ($line1 = <IN1>) { # 対象ファイルをカンマで分解する chomp($line1); $tmp = $line1; $tmp =~ s/(?:\x0D\x0A|[\x0D\x0A])?$/,/; @in1 = map {/^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_} ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g); # 対象ファイルをタブで分解する # @in1 = split("\t",$line1,-1); # ソート(並べ替え)キーとなる項目内容をタブをはさんで連結してキーとする foreach $sortno (@sortkey) { $key .= $in1[$sortno] . "\t"; } #レコードキーが同一でレコードが集約されてしまう場合にセット $key .= sprintf("%08d",$recno); # ソート(並べ替え)キーとソート(並べ替え)キーに対応する # レコード(CSVファイルの各行)をハッシュにセットする if ($in1[0] le "AAJJ") { $sort_record01{$key} = $line1; } elsif ($in1[0] le "AAVV") { $sort_record02{$key} = $line1; } elsif ($in1[0] le "BBJJ") { $sort_record03{$key} = $line1; } elsif ($in1[0] le "BBVV") { $sort_record04{$key} = $line1; } elsif ($in1[0] le "CCJJ") { $sort_record05{$key} = $line1; } elsif ($in1[0] le "CCVV") { $sort_record06{$key} = $line1; } elsif ($in1[0] le "XXJJ") { $sort_record07{$key} = $line1; } elsif ($in1[0] le "XXVV") { $sort_record08{$key} = $line1; } elsif ($in1[0] le "YYJJ") { $sort_record09{$key} = $line1; } elsif ($in1[0] le "YYVV") { $sort_record10{$key} = $line1; } elsif ($in1[0] le "ZZJJ") { $sort_record11{$key} = $line1; } elsif ($in1[0] le "ZZVV") { $sort_record12{$key} = $line1; } $in1_ctr++; $key = undef; } # ハッシュのキーをソート(並べ替え)し、キー順にレコードを出力する foreach $recno (sort keys %sort_record01) { print OUT1 "$sort_record01{$recno}\n"; } foreach $recno (sort keys %sort_record02) { print OUT1 "$sort_record02{$recno}\n"; } foreach $recno (sort keys %sort_record03) { print OUT1 "$sort_record03{$recno}\n"; } foreach $recno (sort keys %sort_record04) { print OUT1 "$sort_record04{$recno}\n"; } foreach $recno (sort keys %sort_record05) { print OUT1 "$sort_record05{$recno}\n"; } foreach $recno (sort keys %sort_record06) { print OUT1 "$sort_record06{$recno}\n"; } foreach $recno (sort keys %sort_record07) { print OUT1 "$sort_record07{$recno}\n"; } foreach $recno (sort keys %sort_record08) { print OUT1 "$sort_record08{$recno}\n"; } foreach $recno (sort keys %sort_record09) { print OUT1 "$sort_record09{$recno}\n"; } foreach $recno (sort keys %sort_record10) { print OUT1 "$sort_record10{$recno}\n"; } foreach $recno (sort keys %sort_record11) { print OUT1 "$sort_record11{$recno}\n"; } foreach $recno (sort keys %sort_record12) { print OUT1 "$sort_record12{$recno}\n"; } close(IN1); close(OUT1);
基本的には[2-4-2.CSVファイルの文字列型昇順ソート]を応用したスクリプトになっています。
入力データの振り分け
# ソート(並べ替え)キーとソート(並べ替え)キーに対応する # レコード(CSVファイルの各行)をハッシュにセットする if ($in1[0] le "AAJJ") { $sort_record01{$key} = $line1; } elsif ($in1[0] le "AAVV") { $sort_record02{$key} = $line1; } elsif ($in1[0] le "BBJJ") { $sort_record03{$key} = $line1; } elsif ($in1[0] le "BBVV") { $sort_record04{$key} = $line1; } elsif ($in1[0] le "CCJJ") { $sort_record05{$key} = $line1; } elsif ($in1[0] le "CCVV") { $sort_record06{$key} = $line1; } elsif ($in1[0] le "XXJJ") { $sort_record07{$key} = $line1; } elsif ($in1[0] le "XXVV") { $sort_record08{$key} = $line1; } elsif ($in1[0] le "YYJJ") { $sort_record09{$key} = $line1; } elsif ($in1[0] le "YYVV") { $sort_record10{$key} = $line1; } elsif ($in1[0] le "ZZJJ") { $sort_record11{$key} = $line1; } elsif ($in1[0] le "ZZVV") { $sort_record12{$key} = $line1; }
[2-4-5.大量のCSVファイルのソートする場合の考慮事項]でソート(並べ替え)キーごとの累計件数から各々100万件程度になるように割り出したソート(並べ替え)キー(原則として第1キー)を指定していきます。入力ファイルの件数によって、elsifの数を調整していきます。また、必要に応じてif文やelsif文には、第2キー以降をand条件で追加していきます。ここでセットした「$sort_recordxx(xxには01から始まる数字が入る)」の順に並べ替えをして出力していきます。
並べ替える件数にあわせて、上記の部分および「foreach $record (@sort_recxx)・・・」で実際に出力している箇所を増減していきます。
同一のソート(並べ替え)キーで100万件を大幅に超える件数がある場合
また、同一のソート(並べ替え)キーで100万件を大幅に超える件数がある場合は、以下のように変更します。
if ($in1[0] le "AAJJ") { $sort_record01{$key} = $line1; }
上記の箇所については、ハッシュにセットするのをやめ、以下のように通常の配列「@sort_record01a」にセットします。
if ($in1[0] le "AAJJ") { $sort_record01a[$in1_ctr] = $line1; }
また、ハッシュからソート(並べ替え)して出力する以下の箇所については、
foreach $recno (sort keys %sort_record01) { print OUT1 "$sort_record01{$recno}\n"; }
以下のように配列「@sort_record01a」から順番に出力するように変更します。
foreach $i (0..$#sort_record01a) { print OUT1 "$sort_record01a[$i]\n"; }