Perl h$数组[$i]; 如果($i_len>$len){ $longest=$i; $len=$i_len; } } 返回$array[$longest]; } 小花生{ 我的$idx=1; my$lastLength=长度$array[0]; my$lastElt=$array[0]; my$listLength=标量@数组; 而($idx$lastLength){ $lastElt=$array[$idx]; $lastLength=$tmpLength } $idx++ } 返回$lastElt; } cmpthese(-10{ 'list_util_xs'=>sub{list_util_xs()}, 'longest_Eric_Storm'=>sub{longest_Eric_Strom()}, 'faster_Eric_Storm'=>sub{faster_Eric_Strom()}, 'David_Precious'=>sub{David_Precious()}, 'MBO'=>sub{MBO()}, 'drewk'=>sub{drewk()}, 'ysth'=>sub{ysth()}, ‘OMG_peanuts’=>sub{OMG_peanuts()}, 'bvr'=>sub{bvr()}, });
这似乎比其他解决方案快得多(基于最快的Eric_Storm) 输出Perl h$数组[$i]; 如果($i_len>$len){ $longest=$i; $len=$i_len; } } 返回$array[$longest]; } 小花生{ 我的$idx=1; my$lastLength=长度$array[0]; my$lastElt=$array[0]; my$listLength=标量@数组; 而($idx$lastLength){ $lastElt=$array[$idx]; $lastLength=$tmpLength } $idx++ } 返回$lastElt; } cmpthese(-10{ 'list_util_xs'=>sub{list_util_xs()}, 'longest_Eric_Storm'=>sub{longest_Eric_Strom()}, 'faster_Eric_Storm'=>sub{faster_Eric_Strom()}, 'David_Precious'=>sub{David_Precious()}, 'MBO'=>sub{MBO()}, 'drewk'=>sub{drewk()}, 'ysth'=>sub{ysth()}, ‘OMG_peanuts’=>sub{OMG_peanuts()}, 'bvr'=>sub{bvr()}, });,perl,algorithm,performance,Perl,Algorithm,Performance,这似乎比其他解决方案快得多(基于最快的Eric_Storm) 输出 Rate list_util_xs fastest_Eric_Storm ysth mpapec list_util_xs 13479/s -- -24% -24% -29% fastest_Eric_Storm 17662/s 31%
Rate list_util_xs fastest_Eric_Storm ysth mpapec
list_util_xs 13479/s -- -24% -24% -29%
fastest_Eric_Storm 17662/s 31% -- -0% -6%
ysth 17680/s 31% 0% -- -6%
mpapec 18885/s 40% 7% 7% --
除非安装了XS版本,否则程序必须停止运行,否则没有必要使用List::Util::XS<代码>使用列表::Util自动加载XS版本(如果可用)。通过“最快”,您指的是执行时间还是编码时间?您是否在尝试优化应用程序?探查器是否真的告诉过您应用程序中的这一行占用了大量的处理时间?至少您应该使用>而不是gt,否则您会得到错误的结果。对我来说,这听起来像是过早的优化。你的名单有多大?真正的应用程序是什么样的?我不知道它有一个名字:)我已经对它进行了基准测试,它比他的reduce在小列表上所做的要慢得多。如果你对一个需要花费一些时间计算的属性进行排序,施瓦茨变换只能节省时间。字符串的长度是已知的,不需要计算任何费用。因此,在这种情况下使用Schwartzian变换是徒劳的。OP正在寻找最快的解决方案,因此任何包含排序的内容(即O(NlogN))都应该比bvr的解决方案中的简单线性搜索(O(N))慢。Schwartzian变换只有在对需要计算时间的属性进行排序时才能节省时间。字符串的长度是已知的,不需要计算任何费用。所以在这种情况下使用Schwartzian变换是徒劳的。我很确定,在我回答的时候,这个问题没有说明我们讨论的是执行时间最快还是最快/最简单的编写方式。至于Schwartzian变换是否可以节省时间,是的,你是对的。我试图避免大量调用length()的开销,但这确实很便宜,快速基准测试表明,直接排序{length($a)length($b)}的速度要快得多。过早的选择确实是万恶之源。对于更长的字符串,长度不会花费更长的时间,utf8字符串除外,即使在那里,我相信它第一次被缓存。报告基准测试时,请始终显示准确的基准测试代码。@ysth:刚刚检查过,您是对的。显然,
length
是常数时间,它可能存储在SV中的某个地方。我假设C的strlen是在后台使用的。不,strlen没有使用,因为perl字符串可以包含nul字符。perl只是跟踪使用了多少字符串缓冲区(除了utf8之外,它等于长度),看起来数组索引减慢了我的第一个版本。令人惊讶的是,临时长度词汇表的创建有点瓶颈。看看我最新的编辑版本,它只调用了两次length。我想第二次调用length
时,隐式$的值可能是从faster
中的第一次调用中缓存的,不是吗?@drewk=>我不确定优化是如何进行的。从ysth的评论来看,Perl似乎在SV中维护了一个存储长度的字段。所以我的猜测是,一旦计算了一次值,即使是无序的查找都将是常数时间。一般来说,测试对内置项的重复调用是否比创建词法副本更快总是一件好事。我已经测试了调用者
,wantarray
,ref
等。大多数情况下,反复给他们打电话要快得多。你需要30多个电话,然后词汇表才能给你带来任何优势。有时人们称之为“高水位线”方法。这就是我们在学习Perl时所做的。距离很小——在一些(不太常见的)运行中,Eric_Storm是最快的。
my @unsorted = qw( one two three four five six seven eight nine ten eleven );
my $idx = 1;
my $lastLength = length $unsorted[0];
my $lastElt = $unsorted[0];
my $listLength = scalar @unsorted;
while ($idx < $listLength) {
my $tmpLength = length $unsorted[$idx];
if ($tmpLength > $lastLength) {
$lastElt = $unsorted[$idx];
$lastLength = $tmpLength
}
$idx++
}
print "Longest element:$lastElt";
Rate REDUCE TMPVAR
REDUCE 169297/s -- -29%
TMPVAR 237926/s 41% --
my $len = length $array[0];
my $longest = 0;
for my $i (1 .. $#array) {
my $i_len = length $array[$i];
if($i_len > $len) {
$longest = $i;
$len = $i_len;
}
}
my $l = $array[$longest];
Rate REDUCE TMPVAR TMPFOR
REDUCE 234862/s -- -0% -7%
TMPVAR 235643/s 0% -- -6%
TMPFOR 251326/s 7% 7% --
Rate TMPVAR TMPFOR REDUCE
TMPVAR 3242/s -- -28% -32%
TMPFOR 4503/s 39% -- -5%
REDUCE 4750/s 47% 5% --
use Benchmark qw(:all);
use List::Util qw(reduce);
my @array = qw( one two three four five six seven eight nine ten eleven ) x 100;
cmpthese(-2, {
REDUCE => sub {
my $l = reduce{ length($a) gt length($b) ? $a : $b } @array;
},
TMPVAR => sub {
my $idx = 1;
my $lastLength = length $array[0];
my $lastElt = $array[0];
my $listLength = scalar @array;
while ($idx < $listLength) {
my $tmpLength = length $array[$idx];
if ($tmpLength > $lastLength) {
$lastElt = $array[$idx];
$lastLength = $tmpLength
}
$idx++
}
my $l = $lastElt;
},
TMPFOR => sub {
my $len = length $array[0];
my $longest = 0;
for my $i (1 .. $#array) {
my $i_len = length $array[$i];
if($i_len > $len) {
$longest = $i;
$len = $i_len;
}
}
my $l = $array[$longest];
},
});
my @array = qw( one two three four five six seven eight nine ten eleven );
my $longest = (
reduce { $a->[1] > $b->[1] ? $a : $b }
map { [ $_, length $_ ] }
@array
)[0];
say $longest;
my @unsorted = qw( one two three four five six seven eight nine ten eleven );
my $longest = (
map { $_->[0] }
sort { $b->[1] <=> $a->[1] }
map { [ $_, length $_ ] } @unsorted
)[0];
say $longest;
sub longest {
my $max = -1;
my $max_i = 0;
for (0 .. $#_) { # for each index
my $len = length $_[$_]; # only get length once per item
if ($len > $max) { # save index and update max if larger
$max = $len;
$max_i = $_;
}
}
$_[$max_i] # return the largest item
}
sub fastest {
my $max = -1;
my $max_ref;
for (@_) {
if (length > $max) { # no temp variable, length() twice is faster
$max = length;
$max_ref = \$_; # avoid any copying
}
}
$$max_ref
}
Rate longest drewk reduce fastest
longest 44245/s -- -21% -30% -47%
drewk 55854/s 26% -- -11% -33%
reduce 63014/s 42% 13% -- -25%
fastest 83638/s 89% 50% 33% --
my $longest = $array[0];
my $len = length $longest;
for my $str (@array) {
if ( length($str) > $len ) {
$longest = $str;
$len = length($str);
}
}
sub drewk {
my $len = -1;
for (@_) {
my $tmp=length($_);
if ( $tmp > $len ) {
$longest = $_;
$len = $tmp;
}
}
return $longest;
}
sub strom {
my $max = -1;
my $max_i = 0;
for (0 .. $#_) { # for each index
my $len = length $_[$_]; # only get length once per item
if ($len > $max) { # save index and update max if larger
$max = $len;
$max_i = $_;
}
}
$_[$max_i] # return the largest item
}
sub red {
return reduce{ length($a) > length($b) ? $a : $b } @_;
}
Rate strom drewk reduce
strom 1323455/s -- -38% -45%
drewk 2144549/s 62% -- -10%
reduce 2390707/s 81% 11% --
David_Precious 64147/s -- -36% -73% -79% -80% -81% -85% -86% -87%
MBO 100195/s 56% -- -58% -67% -69% -70% -77% -79% -80%
OMG_peanuts 237772/s 271% 137% -- -21% -27% -30% -45% -50% -52%
longest_Eric_Strom 300466/s 368% 200% 26% -- -8% -11% -31% -36% -40%
drewk 325883/s 408% 225% 37% 8% -- -4% -25% -31% -34%
bvr 338156/s 427% 237% 42% 13% 4% -- -22% -28% -32%
list_util_xs 434114/s 577% 333% 83% 44% 33% 28% -- -8% -13%
fastest_Eric_Strom 471812/s 636% 371% 98% 57% 45% 40% 9% -- -5%
ysth 497198/s 675% 396% 109% 65% 53% 47% 15% 5% --
#!/usr/bin/env perl
use warnings;
use 5.012;
use Benchmark qw(:all) ;
use List::Util qw(reduce);
my @array = qw( one two three four five six seven eight nine very_long_long ten eleven );
sub list_util_xs {
my $l = reduce{ length($a) > length($b) ? $a : $b } @array;
return $l;
}
sub longest_Eric_Strom {
my $max = -1; my $max_i = 0;
for (0 .. $#array) {
my $len = length $array[$_];
if ($len > $max) {
$max = $len;
$max_i = $_;
}
}
return $array[$max_i];
}
sub fastest_Eric_Strom {
my $max = -1; my $max_ref;
for (@array) {
if (length > $max) {
$max = length;
$max_ref = \$_;
}
}
return $$max_ref;
}
sub David_Precious {
my $longest = ( map { $_->[0] } sort { $b->[1] <=> $a->[1] } map { [ $_, length $_ ] } @array )[0];
return $longest;
}
sub MBO {
my $longest = ( reduce { $a->[1] > $b->[1] ? $a : $b } map { [ $_, length $_ ] } @array )[0];
return $longest->[0];
}
sub drewk {
my $len = -1; my $longest;
for (@array) {
my $tmp=length($_);
if ( $tmp > $len ) {
$longest = $_;
$len = $tmp;
}
}
return $longest;
}
sub ysth {
my $longest = $array[0];
my $len = length $longest;
for my $str (@array) {
if ( length($str) > $len ) {
$longest = $str;
$len = length($str);
}
}
return $longest;
}
sub bvr {
my $len = length $array[0];
my $longest = 0;
for my $i (1 .. $#array) {
my $i_len = length $array[$i];
if($i_len > $len) {
$longest = $i;
$len = $i_len;
}
}
return $array[$longest];
}
sub OMG_peanuts {
my $idx = 1;
my $lastLength = length $array[0];
my $lastElt = $array[0];
my $listLength = scalar @array;
while ($idx < $listLength) {
my $tmpLength = length $array[$idx];
if ($tmpLength > $lastLength) {
$lastElt = $array[$idx];
$lastLength = $tmpLength
}
$idx++
}
return $lastElt;
}
cmpthese( -10, {
'list_util_xs' => sub{ list_util_xs() },
'longest_Eric_Storm' => sub{ longest_Eric_Strom() },
'fastest_Eric_Storm' => sub{ fastest_Eric_Strom() },
'David_Precious' => sub{ David_Precious() },
'MBO' => sub{ MBO() },
'drewk' => sub{ drewk() },
'ysth' => sub{ ysth() },
'OMG_peanuts' => sub{ OMG_peanuts() },
'bvr' => sub{ bvr() },
});
use warnings;
use 5.012;
use Benchmark qw(:all) ;
use List::Util qw(reduce);
my @array = map { ($_) x 50 } qw( one two three four five six seven eight nine ten eleven );
sub list_util_xs {
my $l = reduce{ length($a) > length($b) ? $a : $b } @array;
return $l;
}
sub fastest_Eric_Strom {
my $max = -1; my $max_ref;
for (@array) {
if (length > $max) {
$max = length;
$max_ref = \$_;
}
}
return $$max_ref;
}
sub ysth {
my $longest = $array[0];
my $len = length $longest;
for my $str (@array) {
if ( length($str) > $len ) {
$longest = $str;
$len = length($str);
}
}
return $longest;
}
sub mpapec {
my $max = -1;
my $max_ref;
length > $max and ($max, $max_ref) = (length, \$_) for @array;
return $$max_ref;
}
cmpthese( -10, {
'list_util_xs' => sub{ list_util_xs() },
'fastest_Eric_Storm' => sub{ fastest_Eric_Strom() },
'ysth' => sub{ ysth() },
'mpapec' => sub{ mpapec() },
});
Rate list_util_xs fastest_Eric_Storm ysth mpapec
list_util_xs 13479/s -- -24% -24% -29%
fastest_Eric_Storm 17662/s 31% -- -0% -6%
ysth 17680/s 31% 0% -- -6%
mpapec 18885/s 40% 7% 7% --