配列をスカラコンテキストで評価すると要素数が返ってきますが、リストの要素数を直接的に取得する方法がありません。
なのでリストの要素数を数える方法を色々試してみた結果。
ベンチマークスクリプト
list_count.pl
# !/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw/cmpthese/;
sub get_list { 1 .. 1_000_000 }
cmpthese(
-5,
+{
q/alias/ => sub { sub { 0 + @_ }->(get_list) },
q/anon_array/ => sub { 0 + @{[get_list]} },
q/array/ => sub { 0 + (my @ary = get_list) },
q/empty_assign/ => sub { scalar (() = get_list) },
q/grep/ => sub { scalar grep 1, get_list },
}
);
各手法の説明
-
alias
- 無名サブルーチンに引数として渡し、@_
の要素数を取得 -
anon_array
- 無名配列を作り、その場でデリファレンスして要素数を取得 -
array
- 配列にコピーし、その要素数を取得 -
empty_assign
- 空リストに代入してスカラコンテキストで評価 (http://d.hatena.ne.jp/fbis/20071113/1194931452 を参考にしました) -
grep
- 各要素を恒真式でgrep
した結果をスカラコンテキストで評価
結果
Perl 5.14.2 で走らせた結果は以下の通り:
Rate empty_assign array anon_array grep alias
empty_assign 7.68/s -- -2% -10% -17% -39%
array 7.84/s 2% -- -9% -15% -37%
anon_array 8.57/s 12% 9% -- -7% -31%
grep 9.21/s 20% 18% 8% -- -26%
alias 12.5/s 63% 60% 46% 36% --
まとめ
試した中では alias
が一番速くて、すごいなあと思いました (小並感)。
@_
は実引数のエイリアスなので、要素をコピーするコストがない分速いのだと思われます。
次点は grep
でした。スカラコンテキストの grep
は式が真となるような要素数を返しますが、あまり知られていない気がします。個人的には alias
よりも読み易いので専らこれを使っています。