問題は、変数を適切に宣言していないことです。すべてのスクリプトについて、
use strict; use warnings;
これにより、一般的なエラー ソースが禁止され、あいまいなものについて警告が表示され、すべての変数を適切に宣言することが強制されます。
デフォルトでは、宣言されていない変数はすべてglobalと見なされます。したがって、
for($i=0;$i<=9;$i++)
{
@Space = ();
push(@Hits,\@Space);
}
the@Space
は、各反復で同じ配列を参照します。したがって、 の 10 個のエントリはすべて@Hits
同じ配列への参照です。@Hits
実際どうなのか調べてみましょう。Data::Dumper
またはモジュールを使用してこれを行うことができData::Dump
ます (後者は通常、よりきれいな出力を生成します)。
use Data::Dump; # use Data::Dumper;
dd \@Hits; # print Dumper \@Hits;
取得しますData::Dumper
(理解しやすい):
$VAR1 = [
[
1,
3,
5,
7
],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0],
$VAR1->[0]
];
だから私は、解決策は変数を宣言することだと言いました。具体的には、レキシカル変数が必要です。これらの変数は、宣言されているブロック内でのみ表示されます。これにより、コードに関する推論がはるかに簡単になります。次のように字句変数を宣言できます。
my $foo = 123;
次のようなループがある場合
my @Hits;
for my $i (0 .. 9) {
my @Space;
push @Hits, \@Space;
}
my
が実行されるたびに、新しい @Space
が取得されます。ああ、私は foreach ループを使用しました。0 .. 9
これは、(レキシカル)$i
変数を使用して範囲を反復します。これは、あなたが使用した C スタイルのループよりも理解しやすいと思います。
@Hits
現在のすべての要素が異なる配列参照であるため、期待されるデータ構造が得られます。出力としてData::Dump
:
[[], [1], [], [3], [], [5], [], [7], [], []]
各サブ配列の最初の値を出力するループを実行すると、数字の間の空の行に驚くかもしれません。これは、たとえば、最初の arrayref が index にエントリを持たず、特別な値0
を返すためです。undef
文字列として使用する場合、これは空の文字列です。私のアドバイスに従って をuse warnings
実行すると、初期化されていない値を出力しているというメッセージも表示されます。
これは、定義されているかどうかをテストし、そうでない場合はゼロを提供することで解決できます。perl5 v10 以降、これには defined-or 演算子//
を使用できます (以前の perl では、||
論理 or は do です)。
for my $i (0 .. 9) {
my $value = $Hits[$i][0] // 0;
print "$value\n";
}
他にも改善できる点がいくつかあります。
@Space
配列を手動で作成する必要はありません。のように配列エントリを逆参照するとき、Perl は舞台裏でこれを行います@{ $Hits[$i] }
。これはautovivificationと呼ばれます。
- 範囲だけでなく、配列も反復できます。これは、インデックスをハードコーディングするよりもはるかに優れています。
- v10以降、この機能を使用できます
say
。say
関数はまったく同じですが、print
最後に改行を追加します。
これが私がそのコードを書いた方法です:
#!/usr/bin/perl
use strict; use warnings; use feature 'say';
my @Hits;
for my $i (1, 3, 5, 7) {
push @{ $Hits[$i] }, $i;
}
for my $arrayref (@Hits) {
say $arrayref->[0] // 0;
}
出力:
0
1
0
3
0
5
0
7
(位置 8 と 9 の値は初期化していないため、表示されていないことに注意してください。スライス を繰り返し処理することで、これを修正できます@Hits[0 .. 9]
。)