perl - 在 Perl 中,如何测试一个序列的形式是否为 n、n + 1、n + 2、...、n + k?

标签 perl

我正在尝试实现一个以数组作为参数的子例程(或使用多个参数 - 仍然没有完全理解差异),并根据该数组是否为递增序列返回真或假(每个数字必须是比上一个多1个):

isIncreasingArray(1,2,3,4); # true
isIncreasingArray(1,2,3,1); # false
isIncreasingArray(0,9,1);   # false
isIncreasingArray(-2,-1,0); # true
isIncreasingArray(1,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将返回一个由单个元素组成的列表,因此为真。一个光秃秃的return当您想要返回 false 时就足够了并在所有情况下完成这项工作。

  • 通过比较第一个和最后一个,第二个和倒数第二个等之间的差异,可能可以将比较次数减少一半,以查看差异等于索引的差异,但我现在还没有这么清楚。

    这是根据您的版本略有不同的版本。请注意,您应该使用 strict并确保使用 my 确定循环变量的范围:
    #!/usr/bin/env perl
    
    use strict; use warnings;
    
    use Carp qw(croak);
    use Test::More;
    
    ok(     isSimplyIncreasingSequence( [ 1298 ]  ) ); # true
    ok(     isSimplyIncreasingSequence( [1,2,3,4] ) ); # true
    ok( not isSimplyIncreasingSequence( [1,2,3,1] ) ); # false
    ok( not isSimplyIncreasingSequence( [0,9,1]   ) ); # false
    ok(     isSimplyIncreasingSequence( [-2,-1,0] ) ); # true
    ok( not isSimplyIncreasingSequence( [1,1,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;
    
    }
    

    === 案例:unordered_large_mid
    速率平坦引用
    持平 4.64/s -- -18%
    引用 5.67/s 22% --
    === 案例:ordered_small
    率引用平
    引用 154202/s -- -11%
    平 173063/s 12% --
    === 案例:ordered_large
    速率平坦引用
    持平 2.41/s -- -13%
    引用 2.78/s 15% --
    === 案例:unordered_large_beg
    速率平坦引用
    持平 54.2/s -- -83%
    引用 315/s 481% --
    === 案例:unordered_large_end
    速率平坦引用
    持平 2.41/s -- -12%
    引用 2.74/s 14% --

    关于perl - 在 Perl 中,如何测试一个序列的形式是否为 n、n + 1、n + 2、...、n + k?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8166123/

    相关文章:

    perl - IO::Prompter - 是否可以禁用历史记录?

    perl - 处理简单父子 IPC 的信号和子退出值的组合?

    database - 是否有带数据库逆向工程的 Perl ORM?

    perl - 在大脚本中按词法导入有用的函数

    perl - 将 Perl 中的哈希解析为 CSV 格式

    perl - 为什么引用数组的值没有改变?

    perl - 如何获得函数perl所需的时间?

    perl - 使用 perl 文件处理在 csv 中打印其他语言字符

    perl GetOptions,接受参数的选项触发子例程

    XML::LibXML 在写入 xml 时删除标题