我试图实现一个使用数组作为参数的子例程(或使用多个参数 – 仍然没有完全区分),并且返回true或false,这取决于该数组是否是递增序列(每个数字必须是1以上):
isIncreasingArray(1,2,3,4); # true isIncreasingArray(1,1); # false isIncreasingArray(0,9,1); # false isIncreasingArray(-2,-1,0); # true isIncreasingArray(1,1,1); # false
这是我想出来的:
sub isIncreasingArray { my $last; foreach $n (@_) { return 0 if defined($last) && $last != $n - 1; $last = int($n); } return 1; }
我对Perl很新,我想知道是否有更简单或更简洁的方法来实现这一点?还有,我是按照最佳做法写的?
解决方法
几点:
>为了提高效率,特别是最小化内存占用,您可能希望将对数组的引用传递给子程序。
>在列表上下文中,return 0将返回由单个元素组成的列表,因此将为true。当您要返回false并且在所有上下文中执行该作业时,返回足够的空值。
通过比较第一个和最后一个,第二个和第二个之间的差异等来看比较差异可能会减少一半,以看到差异在索引上的差异,但我现在并没有想到这一点。
这是一个略有不同的版本,基于你的。请注意,您应该使用strict,并确保使用我的循环变量范围:
#!/usr/bin/env perl use strict; use warnings; use Carp qw(croak); use Test::More; ok( isSimplyIncreasingSequence( [ 1298 ] ) ); # true ok( isSimplyIncreasingSequence( [1,4] ) ); # true ok( not isSimplyIncreasingSequence( [1,1] ) ); # false ok( not isSimplyIncreasingSequence( [0,1] ) ); # false ok( isSimplyIncreasingSequence( [-2,0] ) ); # true ok( not isSimplyIncreasingSequence( [1,1] ) ); # false done_testing(); sub isSimplyIncreasingSequence { my ($seq) = @_; unless (defined($seq) and ('ARRAY' eq ref $seq)) { croak 'Expecting a reference to an array as first argument'; } return 1 if @$seq < 2; my $first = $seq->[0]; for my $n (1 .. $#$seq) { return unless $seq->[$n] == $first + $n; } return 1; }
当然还有一些基准:
#!/usr/bin/env perl use strict; use warnings; use Benchmark qw( cmpthese ); use Carp qw( croak ); my %cases = ( ordered_large => [1 .. 1_000_000],ordered_small => [1 .. 10],unordered_large_beg => [5,1 .. 999_000],unordered_large_mid => [1 .. 500_000,5,500_002 .. 1_000_000],unordered_large_end => [1 .. 999_999,5],); for my $case (keys %cases) { print "=== Case: $case\n"; my $seq = $cases{$case}; cmpthese -3,{ 'ref' => sub { isSimplyIncreasingSequence($seq) },'flat' => sub {isIncreasingArray(@{ $seq } ) },}; } sub isSimplyIncreasingSequence { my ($seq) = @_; unless (defined($seq) and ('ARRAY' eq ref $seq)) { croak 'Expecting a reference to an array as first argument'; } return 1 if @$seq < 2; my $first = $seq->[0]; for my $n (1 .. $#$seq) { return unless $seq->[$n] == $first + $n; } return 1; } sub isIncreasingArray { my $last; foreach my $n (@_) { return 0 if defined($last) && $last != $n - 1; $last = int($n); } return 1; }
=== Case: unordered_large_mid Rate flat ref flat 4.64/s -- -18% ref 5.67/s 22% -- === Case: ordered_small Rate ref flat ref 154202/s -- -11% flat 173063/s 12% -- === Case: ordered_large Rate flat ref flat 2.41/s -- -13% ref 2.78/s 15% -- === Case: unordered_large_beg Rate flat ref flat 54.2/s -- -83% ref 315/s 481% -- === Case: unordered_large_end Rate flat ref flat 2.41/s -- -12% ref 2.74/s 14% --