大量のCSVファイルのデータをソート(sort:並べ替え)するのは、本来はデータベース側で行うことであって、Perlで行うことではありません。しかし、実際にはPerlで行うことになる場合もあります。そうした場合にPerlでどのような対応を行うかについて説明していきます。ここで大量のCSVファイルとは、[2-4-2.CSVファイルの文字列型昇順ソート]で並べ替える場合は100万件以上、[2-4-3.CSVファイルの文字列型・数値型/昇順・降順ソート(その1)]で並べ替える場合は10万件以上のCSVデータが1つのファイルに入っていることを前提にしています。これ以上のデータを並べ替える(ソートする)には以下の手順で行います。
まず、並べ替えの方式のどれかを確認します。
1の場合は、以下の手順で行います。
2の場合は、以下の手順で行います。
実際に応用する場合は、入出力データのファイル名を変更し、「@sortkey = (0)」の部分を変更します。この例では、1番目の項目を第1キーとして並べ替えるように指定しています。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);
# keycount.pl
# 内容 :CSV形式のファイルのソート(並べ替え)キーごとの
# 件数と累計件数をカウントする。
# Copyright (c) 2011 Mitsuo Minagawa, All rights reserved.
# (minagawa@fb3.so-net.ne.jp)
# 使用方法 : c:\>perl keycount.pl
#
open(IN1,"input.txt");
open(OUT1,">output.txt");
# ソート(並べ替え)キーの入っている項目番号
@sortkey = (0);
# ソート(並べ替え)用のキー
$key = undef;
# ソート(並べ替え)用のキーと件数をセットするハッシュ
%sort_record = ();
# 累計件数
$total_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";
}
chop($key);
# ソート(並べ替え)キーに該当するキーがあれば、件数を加算する。
if ($sort_record{$key}) {
$sort_record{$key} += 1;
}
# 新たなソート(並べ替え)キーに該当する場合は、初期値1をセットする。
else {
$sort_record{$key} = 1;
}
$key = undef;
}
# ハッシュのキーをソート(並べ替え)し、キー順にレコードを出力する
foreach $recno (sort keys %sort_record) {
$total_ctr += $sort_record{$recno};
$out1 = join("\t",$recno,$sort_record{$recno},$total_ctr);
print OUT1 "$out1\n";
}
close(IN1);
close(OUT1);
ccc,5555 aaa,7777 bbb,9999 aaa,1111 bbb,3333 bbb,4444 aaa,5555 ccc,1111
aaa 3 3 bbb 3 6 ccc 2 8