查找列表中最长元素的最快方法(执行时间)

sid*_*com 13 algorithm perl performance

这是查找列表中最长元素的最快(执行时间)方式吗?

#!/usr/bin/env perl
use warnings;
use 5.012;
use List::Util qw(reduce);
use List::Util::XS;

my @array = qw( one two three four five six seven eight nine ten eleven );

my $l = reduce{ length($a) > length($b) ? $a : $b } @array;

say $l;
Run Code Online (Sandbox Code Playgroud)

Eri*_*rom 17

当只试图找到列表中的一个元素时,不需要构建N大小的数据结构,因为这里有很多答案.O(N)执行此操作的最快方法是遍历阵列,跟踪最大元素.这样你就O(N)可以访问列表和O(1)内存使用情况.

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
}
Run Code Online (Sandbox Code Playgroud)

如果你要多次运行上面的代码,我会建议内联子程序的主体.

编辑:

drewk的基准测试显示,上面代码中的数组索引有点瓶颈.再尝试一下,我终于找到了一种比reduce解决方案更快的方法:

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
}
Run Code Online (Sandbox Code Playgroud)

这导致以下基准:

           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%      --
Run Code Online (Sandbox Code Playgroud)


bvr*_*bvr 6

以下是带有for和更少变量的OMG_peanuts的略微修改版本:

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];
Run Code Online (Sandbox Code Playgroud)

我正在玩基准测试,得到这个小数字(原始阵列)

           Rate REDUCE TMPVAR TMPFOR
REDUCE 234862/s     --    -0%    -7%
TMPVAR 235643/s     0%     --    -6%
TMPFOR 251326/s     7%     7%     --
Run Code Online (Sandbox Code Playgroud)

这对于更大的数字或项目(原始数组x 100)

         Rate TMPVAR TMPFOR REDUCE
TMPVAR 3242/s     --   -28%   -32%
TMPFOR 4503/s    39%     --    -5%
REDUCE 4750/s    47%     5%     --
Run Code Online (Sandbox Code Playgroud)

请注意,算法的适用性因数据细节而有很大差异(我猜测更长的字符串可能会增加length算法中函数的权重).

编辑:这是基准测试的完整代码(长数组版本,x 100数组定义中缺少短)

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];
    },
});
Run Code Online (Sandbox Code Playgroud)

  • 对于更长的字符串,长度不会花费更长的时间,除了utf8字符串,甚至在那里我相信它会在第一次被缓存.报告基准时,请始终显示您的确切基准代码. (2认同)