我试图编写一个脚本来查找3个数字中最大的数字,并通过命令行参数传递它们
我只是想知道我在这段代码中写的错误是什么,感谢您的帮助。
:::
答案 0 :(得分:10)
您的maximum
功能存在缺陷:
$num1
和$num2
都获得第一个,$num3
从未设置。$max
值。chomp
参数。以下是一些代码,它们有五种不同的函数参数检索方法:
sub max1 {
my $num1 = $_[0];
my $num2 = $_[1];
my $num3 = $_[2];
my $max = $num1;
$max = $num2 if $num2 > $max;
$max = $num3 if $num3 > $max;
return $max;
}
sub max2 {
my $num1 = shift;
my $num2 = shift;
my $num3 = shift;
my $max = $num1;
$max = $num2 if $num2 > $max;
$max = $num3 if $num3 > $max;
return $max;
}
sub max3 {
my ($num1, $num2, $num3) = @_;
my $max = $num1;
$max = $num2 if $num2 > $max;
$max = $num3 if $num3 > $max;
return $max;
}
# Works for any number of arguments.
sub max4 {
my $max = shift;
foreach my $foo (@_) {
$max = $foo if $max < $foo;
}
return $max;
}
# Works for any number of arguments.
use List::Util qw( max );
my $n1 = $ARGV[0];
my $n2 = $ARGV[1];
my $n3 = $ARGV[2];
printf "%d\n", max1($n1, $n2, $n3);
printf "%d\n", max2($n1, $n2, $n3);
printf "%d\n", max3($n1, $n2, $n3);
printf "%d\n", max4($n1, $n2, $n3);
printf "%d\n", max($n1, $n2, $n3);
# Even simpler:
printf "%d\n", max1 @ARGV;
printf "%d\n", max2 @ARGV;
printf "%d\n", max3 @ARGV;
printf "%d\n", max4 @ARGV;
printf "%d\n", max @ARGV;
答案 1 :(得分:8)
原始代码中的逻辑错误是有时候第三个数字永远不会被测试。 elsif
应为if
。
您也依赖于隐含的返回值,这会让您感到惊讶。例如,如果您要进入elsif
条件,并且其条件表达式为false,则maximum
函数将返回false值(空字符串),这根本不是什么你真的想要。这是因为如果Perl在子例程中没有命中return
语句,它将返回最后一个表达式的值。在这种情况下,最后一个表达式可以是条件评估。另一个令人惊讶的事情是它可以在条件求值为true的情况下工作,因为在这种情况下,最后一个表达式被分配给$max
,所以这就是返回的内容。
更通用的解决方案将采用任意数量的数字并找到最大值。事实证明,通过使用循环,我们可以消除链式if(){...} elsif()...
语句,同时变得更加灵活。这是一个合理的通用方法,适用于任何大小的数字列表:
sub maximum {
my $max = shift;
foreach my $num (@_) {
$max = $num if $num > $max;
}
return $max;
}
print maximum(1,5,3), "\n"; # Prints 5.
但是还有更好的方法:
use List::Util 'max';
print max(1,5,3), "\n"; # Also prints 5.
List::Util
模块附带Perl,因此您不必安装任何您不应该拥有的模块。
答案 2 :(得分:3)
除了chqrlie's answer之外,我还想向您介绍Perl Modules,让您轻松完成工作。例如,在您的情况下,您可以使用List::Util模块。它是一个核心模块,因此您不必付出额外的努力来安装它。
示例:
#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw( max );
my $maximum = max @ARGV;
print "Maximum: $maximum\n";
答案 3 :(得分:3)
你确实应该使用List::Util::max。但是,仅仅为了多样化,这里有一个获得最多三个参数的简洁方法:
sub max_of_3 {
my $x = $_[ $_[1] > $_[0] ];
return $_[2] > $x ? $_[2] : $x;
}
以下是一些测试代码以及基准测试:
#!/usr/bin/env perl
use strict;
use warnings;
use Algorithm::Combinatorics qw( permutations );
use Dumbbench;
use List::Util qw( max );
use Test::More;
sub dummy { }
sub max_of_3 {
my $x = $_[ $_[1] > $_[0] ];
return $_[2] > $x ? $_[2] : $x;
}
sub classic {
my $num1 = $_[0];
my $num2 = $_[1];
my $num3 = $_[2];
my $max = $num1;
$max = $num2 if ($num2 > $max);
$max = $num3 if ($num3 > $max);
return $max;
}
for my $case ( permutations([5, 6, 7])) {
is max_of_3(@$case), 7, "max of [@$case] is 7";
}
done_testing;
my $bench = Dumbbench->new;
$bench->add_instances(
Dumbbench::Instance::PerlSub->new(
name => 'Dummy',
code => sub { dummy(5, 6, 7) },
),
Dumbbench::Instance::PerlSub->new(
name => 'compact',
code => sub { max_of_3(5, 6, 7) },
),
Dumbbench::Instance::PerlSub->new(
name => 'List::Util::max',
code => sub { max(5, 6, 7) },
),
Dumbbench::Instance::PerlSub->new(
name => 'classic',
code => sub { classic(5, 6, 7) },
),
);
$bench->run;
$bench->report;
基准输出:
Dummy: Ran 21 iterations (0 outliers). Dummy: Rounded run time per iteration: 1.4729e-007 +/- 4.1e-010 (0.3%) compact: Ran 27 iterations (7 outliers). compact: Rounded run time per iteration: 3.8513e-007 +/- 8.4e-010 (0.2%) List::Util::max: Ran 37 iterations (8 outliers). List::Util::max: Rounded run time per iteration: 1.28262e-007 +/- 2.3e-011 (0.0%) classic: Ran 27 iterations (7 outliers). classic: Rounded run time per iteration: 5.81187e-007 +/- 9.2e-011 (0.0%)
故事的道德:1)使用完善的图书馆,而不是自己动手。这里List::Util::max
比调用一个什么都不做的子程序要快,因为它是在XS中实现的; 2)除非你能提出一个非常非常好的理由,否则更喜欢清晰度而不是紧凑性。在大多数情况下,即使速度提高35%也是不值得的,特别是因为使用List::Util::max
同时更清晰,更紧凑和它的性能优于两种手动选择。您也不必编写新代码来处理 N 参数。