试图打印数组的一个元素以某种方式打印所有元素

nhe*_*shy 2 arrays perl

我正在编写一个脚本来从文件中获取整数列表aryData,对它们进行排序,打印排序的数组,最高值和最低值.

aryData

89 62 11 75 8 33 95 4
Run Code Online (Sandbox Code Playgroud)

但是,当打印最高或最低值时,将打印阵列的所有元素.

这是我的Perl代码

#!/bin/perl

use strict;
use warnings;

print "Enter filename to be sorted: ";
my $filename = <STDIN>;
chomp( $filename );

open( INFILE, "<$filename" );
my @nums = <INFILE>;
close INFILE;

my @sorted = sort { $a cmp $b } @nums;

open my $outfile, '>', "HighLow.txt";

print $outfile "Sorted numbers: @sorted";
print $outfile "Smallest number: $sorted[0] \n";
print $outfile "Largest number: $sorted[-1] \n";
Run Code Online (Sandbox Code Playgroud)

产量 HighLow.txt

Sorted numbers: 89 62 11 75 8 33 95 4
Smallest number: 89 62 11 75 8 33 95 4
Largest number: 89 62 11 75 8 33 95 4
Run Code Online (Sandbox Code Playgroud)

sim*_*que 5

这个答案将有很大一部分代码审查和解释与问题没有直接关系的概念.

让我们看一下读入数组的代码部分.

open(INFILE, "<$filename");
my @nums = <INFILE>;
close INFILE;
Run Code Online (Sandbox Code Playgroud)

这段代码适合您正在做的事情,但它有一些安全性和样式问题,我将在下面进一步介绍.

所以你有一个文件名,你逐行阅读文件.每行都进入数组中的一个元素@nums.由于你的东西没有按照你想要的方式工作,你需要调试的第一步是尝试查看数组.

你尝试这样做并不是一个坏主意.

print "Sorted numbers: @sorted";
Run Code Online (Sandbox Code Playgroud)

内插在双引号的阵列""在Perl串加入与变量阵列的元素$,,其也被称为输出字段分隔符.默认情况下,它是一个空格.

my @foo = (1, 2, 3);
print "@foo";
Run Code Online (Sandbox Code Playgroud)

This will give the following output

1 2 3
Run Code Online (Sandbox Code Playgroud)

Unfortunately your input file already had spaces as separators, and all numbers were on one line. So you couldn't really see that the array wasn't properly set up. That's one of those facepalm moments when you notice it yourself. You could have noticed it by looking at the sorted numbers. You did sort them, but they were not sorted.

Sorted numbers: 89 62 11 75 8 33 95 4
Run Code Online (Sandbox Code Playgroud)

A better way to figure out what's in the array would be to use Data::Dumper, which lets you serialize data structures. It's included with Perl.

use Data::Dumper;

my @foo = (1, 2, 3);
print Dumper \@foo;
Run Code Online (Sandbox Code Playgroud)

The module gives you a Dumper功能.它喜欢在引用上更好地工作,所以你需要添加反斜杠来创建引用@foo.在这一点上,这意味着什么并不重要.请记住,如果你的变量没有$,你在前面放一个反斜杠.

$VAR1 = [
          1,
          2,
          3
        ];
Run Code Online (Sandbox Code Playgroud)

这很有用.它告诉我们三个要素.现在让我们来看看你的代码.我使用伪文件句柄而不是实际文件,该文件句柄DATA__DATA__程序末尾的部分读取.这非常适合测试和示例.

use Data::Dumper;

my @nums = <DATA>;
my @sorted = sort { $a cmp $b } @nums;

print Dumper \@sorted;

__DATA__
89 62 11 75 8 33 95 4
Run Code Online (Sandbox Code Playgroud)

这打印

$VAR1 = [
          '89 62 11 75 8 33 95 4
'
        ];
Run Code Online (Sandbox Code Playgroud)

我们在这里可以看到两件事.首先,所有数字都在一行上,因此它们进入第一个元素.其次,该行最后有一个换行符.您已经知道可以删除它chomp.

所以我们试着解决这个问题.我们现在知道我们需要split数字线.有许多不同的方法可以完成这项任务.我会用一个非常详细的解释所涉及的步骤.

use Data::Dumper;

my $line = <DATA>;    # only read one line
chomp $line;          # remove the line ending

my @nums = split / /, $line;
my @sorted = sort { $a cmp $b } @nums;

print Dumper \@sorted;

__DATA__
89 62 11 75 8 33 95 4
Run Code Online (Sandbox Code Playgroud)

我们使用split模式 / /将数字字符串转换为数字列表,并将其放入数组中.然后我们排序.

$VAR1 = [
          '11',
          '33',
          '4',
          '62',
          '75',
          '8',
          '89',
          '95'
        ];
Run Code Online (Sandbox Code Playgroud)

如您所见,我们现在有一个排序的数字列表.但它们没有按数字排序.相反,它们按照空间排序.那是因为cmp运算符ASCII字符编号排序.它也是Perl的默认行为sort,因此您可以省略整个{ $a cmp $b }块.它就像说的一样sort @nums.

但我们希望按数值对数字进行排序,因此我们需要使用<=>排序运算符.

use Data::Dumper;

my $line = <DATA>;    # only read one line
chomp $line;          # remove the line ending

my @nums = split / /, $line;
my @sorted = sort { $a <=> $b } @nums;

print Dumper \@sorted;

__DATA__
89 62 11 75 8 33 95 4
Run Code Online (Sandbox Code Playgroud)

现在程序打印出正确的输出.

$VAR1 = [
          '4',
          '8',
          '11',
          '33',
          '62',
          '75',
          '89',
          '95'
        ];
Run Code Online (Sandbox Code Playgroud)

我会留给你把它放回你的实际程序中.


最后,关于你的一句话open.您使用的是所谓的glob文件句柄.那些东西就像INFILE是全局标识符.它们在整个程序中都有效,即使在您可能加载的其他模块中也是如此.虽然在这个微小的程序中并没有真正有所作为,但它可能会在将来引发问题.例如,如果Data :: Dumper模块是打开一个文件并使用相同的标识符INFILE,并且你没有调用过close INFILE,那么你的程序可能会崩溃或做很奇怪的事情,因为它会重用相同的句柄.

相反,您可以使用词法文件句柄.词法变量仅在某个范围内有效,如函数或循环体.它只是一个常规变量,用声明my.close当它超出范围时,它会自动呼叫你.

open my $fh, "<foo";
my @nums = <$fh>;
close $fh;
Run Code Online (Sandbox Code Playgroud)

open用两个参数调用.这也不是一个好主意.现在你有了这种模式<,但是如果你把它留下来做open my $fh, "$file"$file从用户那里读取,他们可能会传递不好的东西,比如| rm -rf slash.然后Perl将管道|视为模式,打开管道并删除所有东西.相反,使用三参数打开.

open my $fh, '<', 'foo';
Run Code Online (Sandbox Code Playgroud)

现在你明确设置了模式,你就安全了.

最后一点是你应该经常检查是否open有效.这很简单.

open my $fh, '<', 'foo' or die $!;
Run Code Online (Sandbox Code Playgroud)

变量$!包含open遇到的错误.该or如果返回值只会触发open电话是假的.而die使得程序终止.您可能收到的错误可能如下所示.

/home/foo/code/scratch.pl第6154行没有这样的文件或目录.

所以完整的文件读取应该是这样的.

open my $fh, '<', $filename or die "Could not read $filename: $!";
my @nums = <$fh>;
close $fh;
Run Code Online (Sandbox Code Playgroud)