Perl:配列用の「$#変数」について

昨日の続きで配列要素数を出力する「$#変数名」について調べてみました。
「$#変数名」は処理が遅いので配列を扱う上でもっとも速度や作業性のよさそうなループを調べました。

ループで処理の早かった順に

1番目(10秒間に3980回)
@abc=(1..1000);
my $count=$#abc;
foreach my $i(0 .. $count){}
※ループ内で配列の追加は出来ない

2番目(10秒間に3972回)
@abc=(1..1000);
foreach my $i(0 .. $#abc){}
※ループ内で配列の追加は出来ない

3番目(10秒間に3966回)
@abc=(1..1000);
foreach my $value(@abc){}
※ループ内で配列の追加が可能

4番目(10秒間に2820回)
@abc=(1..1000);
my $count=$#abc;
for(my $i=0;$i<=$count;$i++){}
※ループ内で配列を追加可能だが、追加時は$countも加算する事

5番目(10秒間に2783回)
@abc=(1..1000);
my $count=$#abc;
my $i=0;
while($i<=$count){$i++;}
※ループ内で配列を追加可能だが、追加時は$countも加算する事

6番目(10秒間に1458回)
@abc=(1..1000);
for(my $i=0;$i<=$#abc;$i++){}
※ループ内で配列の追加が可能

7番目(10秒間に1447回)
my $i=0;
while($i<=$#abc){$i++;}
※ループ内で配列の追加が可能

となりました。
(「10秒間でxxx回」は当方のシステムの10秒間で実行できた回数です、他のプロセスの動作してる環境下なので誤差はあり)

1番目と2番目のforeachは、配列数「$#変数」を通常変数$countに代入してからループに使ってるかそのままかの違いですが、foreachは計算部分をメモリに記録してから処理を開始するようなのでどちらでも処理速度の差は無くとても高速ですが、欠点としてループ内で配列を追加しても実行時の配列までしかループしてくれません。

3番目のforeachは値を要素を$valueに取り出してるのため、ループ内で$abc[$i]とか書かなくて良いので処理内容によっては1番早いかも(下記※1)、またループ内で配列も追加可能なのでカウンターが無い事を除けば使い勝手がよさそうです。(下記※2※3)

4番目と6番目のforは、配列数「$#変数」を通常変数$countに代入してからループに使ってるかそのままかの違いですが倍の速度差があります。

5番めと7番目のwhileは、一般的な使い方では無いので参考までに書いたものです。

備考
※1:文字を出力する場合
1番目の{}内に「$str=$abc[$i];」を記述時
→10秒間に1541回
3番目の{}内に「$str=$value;」を記述時
→10秒間に2049回
となりましたので要素を取り出すなら1番や2番より3番が早いです。

※2:3番目にカウンター追加すると
3番目に「my $i=0;」と{}内に「$i++;」を記述時
→10秒間に2594回
となりましたのでカウンターが必要なら1・2・4番の方が早いです。

※3
上記※1と※2の複合でカウンターとデータ両方出力する場合
1番目の{}内に「$str=$abc[$i];$num=$i;」を記述時
→10秒間に1083回
3番目の「my $i=0;」と{}内に「$str=$value;$num=$i++;」を記述時
→10秒間に1085回
ほとんど大差ありませんが、3番目は$abc[$i]が通常変数に代入済みなので1ループ中で何度も読み出す場合に有利です。

結論
通常の使用条件であれば、備考※1「要素のみ出力」の3番目がもっとも高速である、カウンター出力を追加した場合は備考※3の1番目(同等の2番目)か3番目が高速、中でも3番目は上記にもあるが何度も変数を使う場合に有利で要素を追加できるメリットもあり一番良さそうだが、カウンターを使う場合は{}の前(ループの外側)で変数の宣言しなければならず局所化と言う意味ではスマートでは無いのが弱点。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA