【问题标题】:Perl calculate average from randomly populated arrayPerl 从随机填充的数组中计算平均值
【发布时间】:2016-05-11 04:24:24
【问题描述】:

我有一个需要帮助的学校作业。现在,我知道你在想什么,但我的老师不在城里,没有回复我的电子邮件,我的其他同学也不知道如何解决这个问题。一些指针和提示将不胜感激!

作业是这样的:

我们应该创建一个数组,用 20 到 30 个 1-100 范围内的随机整数填充它。然后,在子程序的帮助下,我们应该计算这些数字的平均值。

当我回调子程序时出现问题,这给了我答案 0 或“非法除以 0”错误。我现在的代码是这样的:

#! /usr/bin/perl -w

use warnings;
use strict;

# Declaring the scalar variables and arrays.
my @AllNumbers;

# Create random data set of between 20 to 30 measures used for the 100 random intigers.
my $random_number = int( rand( 31 - 20 ) ) + 20;

# Create random data set of 100 intigers.
for ( my $i = 0 ; $i <= $random_number ; $i++ ) {
    $AllNumbers[$i] = int( rand( 100 - 1 ) );
}

# Print the 20 to 30 random numbers (range 1 - 100).
print("Your random numbers are: \n@AllNumbers");

sub average {
    my $ArrayAverage = @_;
    for (@_) {
        my $total += $_;
    }
    return $ArrayAverage / $random_number;
} ## end sub average

# Print the mean/average of the 20-30 numbers.
print( "\n\nThe average of those random numbers is: ", &average, "\n\n" );

现在,正如我所说,我想自己解决这个问题,我已经花了整整两天的时间,但无论我做什么似乎都无法解决它。任何提示将非常感谢。附:应该提到的是,我们不应该使用任何模块/插件。

【问题讨论】:

  • 顺便说一句,如果您需要 @AllNumbers 的覆盖范围为 1 -100,则应该以不同的方式完成。因为这个rand(100-1)rand(99) 相同,它为您提供0 - 98 的范围。您需要进一步研究并修复它;)
  • Stack Overflow 不禁止家庭作业协助。只是我们会帮助您理解它(并找出问题所在),而不是为您做。

标签: arrays perl


【解决方案1】:

我首先要解决几个风格点:

  • 将您的 sub 放在开头(或者如果必须,放在结尾)。把它放在代码中间很麻烦。

  • 不要使用&amp; 调用子例程 - 这是不好的风格,并且会导致一些奇怪的行为。在你的情况下:&amp;average 被有效地调用,没有参数。但总的来说它很糟糕,除非您明确知道为什么要这样做,否则不要使用它。 (它确实有一些用途,但是当你看到它们时你会知道——而且你不会在你早期学习perl 时知道)。

  • 这样的数组大写不是很好的形式,因为这就是模块/包的命名方式。如果可以的话,坚持使用小写变量。

  • 您的 for 循环是 C 风格,可以使用,但最好写成 for ( 1..$random_number ) {,因为您不需要迭代器。

  • shebang 线上不需要-w,因为你有use warningsuse warnings; 是更好的方法。

  • 调用变量$random_number 不是很有帮助 - 我们可以看到,因为它分配了rand 的结果。称它为它的用途 - 比如$number_of_elements

  • 假设您只需要使用一次$random_number,您可能不需要将其粘贴到变量中。你可以,如果你觉得它有助于可读性(这是一个品味问题——在良好的编程中,清晰易读是唯一真正重要的事情——考虑到当今编译器的状态,大多数内存/性能都是过早的优化。)

您的核心问题是:

my $ArrayAverage = @_;

这会将$ArrayAverage 设置为列表中的元素数。这将始终与$random_number 相同,因为这是您迭代的次数。

您在此处迭代元素,但实际上并未使用 $total

for (@_) {
    my $total += $_;
}

所以在这里 - 您返回数组中的元素数除以数组中的元素数。

return $ArrayAverage / $random_number;

但真正重要的是 - 这些都不重要,因为您使用 &amp;average 调用它实际上并没有发送任何参数。所以你只是输入零,然后输出零。

了解一下可能很有用 - 标量上下文中的数组返回元素的数量,因此计算平均值很简单:

my $sum; 
$sum += $_ for @AllNumbers; 
print( "\n\nThe average of those random numbers is: ", $sum / @AllNumbers, "\n\n" );

这将产生一个长小数 - 如果您需要对其进行格式化,您可以使用 printfsprintf

printf( "\n\nThe average of those random numbers is: %02.2f \n\n", $sum / @AllNumbers);

所以我会稍微改写成这样:

#!/usr/bin/perl

use warnings;
use strict;

# Declaring the scalar variables and arrays.
my @all_numbers;


#repeat 20 + random 11 times - so 20-30
for ( 1 .. 20 + int rand 11 ) { 
    push ( @all_numbers, int rand 99 );
}

# Print the 20 to 30 random numbers (range 1 - 100).
print("Your random numbers are: \n@all_numbers\n");

#calculate sum of elements
my $sum; 
$sum += $_ for @all_numbers;

print "Sum: $sum count: ", scalar @all_numbers, "\n"; 

# Print the mean/average of the 20-30 numbers.
printf( "\n\nThe average of those random numbers is: %02.2f \n\n", $sum / @all_numbers);

【讨论】:

  • 哇,谢谢!这些信息会派上用场。这么多,我们的老师没有教我们......
  • 好吧,至少你明白了重要的一点——如何自己尝试,并在 Stack Overflow 上提出一个体面的问题。这本身就是一种有价值的编程技术! :)
【解决方案2】:

用惯用的 Perl 编写它会给你这样的东西:

#!/usr/bin/perl

use warnings;
use strict;

my @numbers;

my $how_many = int(rand 11) + 20;

push @numbers, int(rand 100) + 1 for 1 .. $how_many;

print "Your random numbers are: \n@numbers\n";
print "The mean of those numbers is: ", average(@numbers), "\n";

sub average{
  my $total;
  $total += $_ for @_;
  return sprintf '%.2f', $total / @_;
}

【讨论】:

    【解决方案3】:

    干得好,到目前为止!几乎没问题。但是你调用你的平均函数没有 任何参数 (&amp;average)。像这样尝试:

    sub average{
        my @Array_To_Average = @_; # this is now a local copy of the global @AllNumbers
        my $total = 0;
        for (@Array_To_Average) # iterate over the local copy ...
        { 
            $total += $_; # ...and sum up
        }
        return $total / $random_number;
    
        # instead of $random_number you could also use
        # scalar(@Array_To_Average). That's the number of items
        # in the array, i.e.
        #   return $total / scalar(@Array_To_Average);
    }
    
    print ("\n\nThe average of those random numbers is: ", average(@AllNumbers), "\n\n");
    

    调用函数时请省略&amp;。那是很古老的风格。 更喜欢大多数其他语言中使用的样式:

    my $result1 = some_function();
    my $result2 = some_other_function($param1, $param2);
    

    【讨论】:

    • 非常感谢您的帮助!我不敢相信我错过了。另外,关于scalar(@Array_To_Average); 的好建议,我不知道这是一件事......
    • 如果您需要强制使用标量上下文,则需要 scalar。特别是在打印时。 (print 默认为列表上下文)。如果您正在执行数字操作(例如 $num / @array),则标量上下文已经存在,因此您不需要它。
    【解决方案4】:

    在寻求帮助之前,您尝试自己动手,做得很好!

    要调试您的代码,请尝试添加一些打印以最小化您需要在其中查找错误的区域。因此,在这种情况下,您可以在平均 sub 中添加 print $random_number,您会发现它设置正确。如果您打印 $ArrayAverage 的元素,您会发现它没有值,这仅仅是因为您需要将 @AllNumbers 数组传递给 &average 子,当您在脚本最后一行的 print 中调用它时.

    所以解决方案是你只需要在被调用时将@AllNumbers 数组传递给 &average():

    print ("\n\nThe average of those random numbers is: ", &amp;average(@AllNumbers), "\n\n");

    这应该可以正常工作;)祝你好运!

    【讨论】:

    • 其实问题还不止这个。
    • 在原始代码中,$total 每次循环都重置为 0。
    • 好收获!我没有注意到那个,我注意到 rand(99) 错误的范围但错过了这个。感谢您的来信!
    【解决方案5】:

    (主要)问题是您调用 sub 时没有参数! 试试这个:

    average($_) foreach @AllNumbers;
    
    my $count = 0;
    my $total;
    my $average;
    
    sub average{
        my $num = shift;
        $count++; # count number of random numbers 
        $total += $num; # sum up
        $average = $total/$count; # calculate average
        return $average;
    }
    
    # Print the mean/average of the 20-30 numbers.
    print ("\n\nThe average of those random numbers is: ", $average, "\n\n");
    

    【讨论】:

    • 我不相信这是执行average 函数的好方法。我可能会将整个数组传递给它,并让它返回平均值。或者使用迭代器。但是在 sub 外面有一个my $average,然后你返回它似乎有点奇怪。
    【解决方案6】:

    让它工作来帮助你。

    #! /usr/bin/perl -w
    
    use warnings;
    use strict;
    
    # Declaring the scalar variables and arrays.
    my @AllNumbers;
    my $avgOfArray;
    
    # Create random data set of between 20 to 30 measures used for the 100         random intigers.
    my $random_number = int(rand(31 - 20)) + 20;
    
    # Create random data set of 100 intigers.
    for(my $i = 0; $i <= $random_number; $i++){
        $AllNumbers[$i] = int(rand(100 - 1));
    }
    
    # Print the 20 to 30 random numbers (range 1 - 100).
    print ("Your random numbers are: \n@AllNumbers");
    sub average {
        my @array = @_; # save the array passed to this function
        my $sum; # create a variable to hold the sum of the array's values
        foreach (@array) { $sum += $_; } # add each element of the array
        # to the sum
        return $sum/@array; # divide sum by the number of elements in the
        # array to find the mean
    }
    $avgOfArray = average(@AllNumbers);
    
    # Print the mean/average of the 20-30 numbers.
    print ("\n\nThe average of those random numbers is: ",  $avgOfArray,     "\n\n"); here
    

    【讨论】:

      【解决方案7】:

      您需要将参数传递给您的average 子例程:

      #!/usr/bin/perl
      
      sub average{
        my $tot;
        $tot += $_ for @_;
        return sprintf '%.3f', $tot / @_;
      }
      my @num;
      
      my $quantity = int(rand 11) + 20;    
      push @num, int(rand 100) + 1 for 1 .. $quantity;
      
      print "Random numbers: \t@num\n";
      print "Average: ", average(@num), "\n";
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-25
        相关资源
        最近更新 更多