2009年03月29日 23:45 [Edit]
perl - for(;;)よりforeach
何が気になるかというと、for(;;)の利用。それもCやJavaScriptなど、事実上それしかないソースからそのまま転写したとかならとにかく、編集距離 (Levenshtein Distance) - naoyaのはてなダイアリーでは Python版がちゃんとxrangeを使っているのにPerl版がfor(;;)のでますます解せない。
"Perl Best Practices"でも、読みやすさの観点からCスタイルのforは避けよ(pp. 100-101)と言っているが、もう一つ損なわれるものがある。速度である。
#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw/cmpthese timethese/;
for my $e ( 0 .. 6 ) {
my $n = 10**$e;
print "#### loop $n times\n";
cmpthese(
timethese(
0,
{
for => sub {
my $dummy;
for ( my $i = 0 ; $i < $n ; $i++ ) { $dummy += $i }
},
foreach => sub {
my $dummy;
foreach my $i ( 0 .. $n - 1 ) { $dummy += $i }
}
}
)
);
}
上はループ回数1回から100万回までベンチマークするスクリプトであるが、以下の結果を見てほしい。
#### loop 1 times
Rate foreach for
foreach 466071/s -- -50%
for 929903/s 100% --
#### loop 10 times
Rate for foreach
for 223832/s -- -11%
foreach 250507/s 12% --
#### loop 100 times
Rate for foreach
for 27522/s -- -40%
foreach 45676/s 66% --
#### loop 1000 times
Rate for foreach
for 2898/s -- -45%
foreach 5238/s 81% --
#### loop 10000 times
Rate for foreach
for 289/s -- -45%
foreach 527/s 82% --
#### loop 100000 times
Rate for foreach
for 28.5/s -- -43%
foreach 50.5/s 77% --
#### loop 1000000 times
Rate for foreach
for 2.24/s -- -40%
foreach 3.70/s 66% --
ループ一回の場合を除き、すべてforeachが勝っており、それもかなり無視できない差である。ここまで差があるとは私も思わなかった。
ちなみに1..1e6とかやっても、foreachでは百万要素の配列を作ったりしないので安心していい。これは「404 Blog Not Found:perl - for(1..1e10) と Iterator」でも以前指摘している。
さらに付け加えると、今回のlevenshtein_distance()では、substr()を使えば文字ばらしの必要はなく、かえってすっきりと書くことが出来し。二次元配列は$m->[$x][$y]よりも$m[$x][$y]とレファランスを一つ減らした方がわずかではあるが速く、可読性もあまり失われない。以下、実例。
sub levenshtein_distance {
my ( $s1, $s2 ) = @_;
my @m;
$m[$_][0] = $_ for ( 0 .. length $s1 );
$m[0][$_] = $_ for ( 0 .. length $s2 );
for my $i ( 1 .. length $s1 ) {
for my $j ( 1 .. length $s2 ) {
my $diff =
substr( $s1, $i - 1, 1 ) eq substr( $s2, $j - 1, 1 ) ? 0 : 1;
$m[$i][$j] = min(
$m[ $i - 1 ][ $j - 1 ] + $diff,
$m[ $i - 1 ][ $j ] + 1,
$m[ $i ][ $j - 1 ] + 1
);
}
}
return $m[-1][-1];
}
Dan the Perl Monger
Posted by dankogai at 23:45│Comments(4)│TrackBack(0)
この記事へのトラックバックURL
この記事へのコメント
substr()じゃなくばらしてあるのは、
一般的なオブジェクトの配列も意識してあるからだと思います。
一般的なオブジェクトの配列も意識してあるからだと思います。
Posted by あああ at 2009年03月30日 06:37
しかしまあ(どっちにしても、なんだが)あらためて並べてみるとPerlのコードってえのはキッタねえなあ。
Posted by shou at 2009年03月30日 14:03
相変わらず汚くて吐き気がしますね(苦笑)
Posted by b at 2009年03月30日 18:14
あーあ怒らせてしまいましたね
ttp://naoya.g.hatena.ne.jp/naoya/20090330/1238367025
ttp://naoya.g.hatena.ne.jp/naoya/20090330/1238367025
Posted by a at 2009年03月31日 20:43
