3

10 個の 1 次元配列を作成し、これら 10 個の 1 次元配列を別の 1 次元配列に配置し、いくつかのデータを配列の特定のインデックスに格納したいと考えています。

しかし、私が期待する出力は

expect output         real output
    0                      1
    1                      1
    0                      1
    3                      1
    0                      1
    5                      1
    0                      1
    7                      1
    0                      1
    0                      1

ここに私のコードがあります

@Hits = ();

# Create 10 one dimension array
for($i=0;$i<=9;$i++)
{
    @Space = ();
    push(@Hits,\@Space);
}

# Store some data to some index
push(@{$Hits[1]},1);
push(@{$Hits[3]},3);
push(@{$Hits[5]},5);
push(@{$Hits[7]},7);

# print the first element of 10 arrays
for($i=0;$i<=9;$i++)
{
    print $Hits[$i]->[0];
    print "\n";
}

ありがとう

4

3 に答える 3

6

問題は、変数を適切に宣言していないことです。すべてのスクリプトについて、

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以降、この機能を使用できますsaysay関数はまったく同じですが、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]。)

于 2013-07-27T09:17:38.943 に答える
1

次のようにコードを変更します。

#! /usr/bin/perl -w
@Hits = ();

push(@{$Hits[1]},1);
push(@{$Hits[3]},3);
push(@{$Hits[5]},5);
push(@{$Hits[7]},7);

#print the content of
for($i=0;$i<=9;$i++)
{
    if (defined ($Hits[$i])) {
        print "$Hits[$i][0]\n";
    } else {
        print "0\n";
    }
}

@Hits に @space の参照を与えるのは正しくなく、間違った結果になります。perl で @Hits を初期化する必要はありません。

于 2013-07-27T07:29:13.327 に答える
0
perl -e "use Data::Dump; @sf=(); push @{$sf[0]},"0"; push @{$sf[1]},"1"; dd \@sf;"
[[0], [1]]

また

perl -e "use Data::Dump; @sf=(); push @sf,["0"]; push @sf,["1"]; dd \@sf;"
[[0], [1]]
于 2014-10-11T15:22:59.357 に答える