プロが教えるわが家の防犯対策術!

perlで大容量CSVのsort方法について


perlでcsvファイル100MB超のファイルをソートしたいと思ってますが、以下の方法でメモリーの関係上(と思ってます。)できません。

ソートを行う方法がありますでしょうか?
件数も11万件あるので、エクセルでソートしてからの受け渡しが出来ずに悩んでます。

(ここから)
#sortロジック
sub sort {
use warnings;
use feature ':5.10';

open my $ifh, '<', $inport or &error("Can't open $inport");
my @lines = <$ifh>;
close $ifh;

print @lines, "\n";
#csvファイル何番目?

my @sorted = map { $_->[0] }
sort { $b->[0] <=> $a->[0]}
map { [(split q{,}, $_)[0], $_] }
@lines;

@lines = @sorted;
exit;
}
(ここまで)

いつも貴重なアドバイスをありがとうございます。よろしくお願いいたします。

A 回答 (3件)

ファイルを1度に読み込まずに、while ループで読み込んでソートキーをハッシュのキーに割り当て、ハッシュの配列に保存して、一定数になったらファイルに保存して、最後にまとめればそれほどメモリは必要ないと思います。



my %sorted;

while (my $line = <$fh>) {
my $key = (split /,/, $line)[0];
push @{$sorted{$key}}, $line;
if (@{$sorted{$key}} == 1000) {
open OUT, ">>$key.tmp" or die "Can't open: $!";
print OUT @{$sorted{$key}};
close OUT;
@{$sorted{$key}} = ();
}
}

open OUT, ">out.txt" or die "Can't open: $!";
foreach my $key (sort { $b <=> $a } keys $sorted) {
if (-e "$key.tmp") {
open IN, "$key.tmp" or die "Can't open: $!";
print OUT while <IN>;
close IN;
}
print OUT @{$sorted{$key}} if @{$sorted{$key}};
}
close OUT;
    • good
    • 0
この回答へのお礼

早速やってみました。
すごいです!!
無事動作させることが出来ました!!
140MBを超えるデータですが、1分かからないで終わります。
こんなにパフォーマンスが向上する方法があるのかと目から鱗です。
いつも助かります。ありがとうございました。

お礼日時:2010/06/26 23:15

> foreach my $key (sort { $b <=> $a } keys $sorted) {



No2 です。1つ誤記がありました。訂正します。

foreach my $key (sort { $b <=> $a } keys %sorted) {
    • good
    • 0
この回答へのお礼

訂正ありがとうございます。
助かります。

お礼日時:2010/06/26 23:13

メモリが無理なら、ファイルに頼るしかないでしょう。



ファイルのような外部記録を使ったソートアルゴリズムには自然マージソートがあります。
この方法だと、1行ずつ処理すればいいので、メモリはそれほど使いません。

CPANのFile::Sortモジュールがmerge sortのようです。
http://search.cpan.org/~cnandor/File-Sort-1.01/S …

あるいは、Cとかのソースは見付かるので、自分で作ってもいいでしょう。
    • good
    • 0
この回答へのお礼

いつもアドバイスありがとうございます。
File::Sortモジュールについて少し調べてやってみようと思いましたが、うまくいきませんでした。
サーバーがこのモジュールがないのかもしれませんので確認をしてみようと思います。

お礼日時:2010/06/26 23:12

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!