如何将数据推送到多维数组?

use*_*116 2 perl reference multidimensional-array

我想创建10个一维数组,并将这10个一维数组放到另一个一维数组中,并将一些数据存储到某个特定的数组索引中.

但是我期望的输出应该是

expect output         real output
    0                      1
    1                      1
    0                      1
    3                      1
    0                      1
    5                      1
    0                      1
    7                      1
    0                      1
    0                      1
Run Code Online (Sandbox Code Playgroud)

这是我的代码

@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";
}
Run Code Online (Sandbox Code Playgroud)

谢谢

amo*_*mon 6

问题是你没有正确地声明你的变量.对于每个脚本,你应该

use strict; use warnings;
Run Code Online (Sandbox Code Playgroud)

这不允许常见的错误来源,警告iffy东西,并强制您正确声明所有变量.

默认情况下,所有未声明的变量都被视为全局变量.因此,在

for($i=0;$i<=9;$i++)
{
    @Space = ();
    push(@Hits,\@Space);
}
Run Code Online (Sandbox Code Playgroud)

@Space是指在每次迭代中相同的阵列.因此,所有十个条目@Hits都是对同一个数组的引用.我们来看看@Hits究竟是什么.我们可以使用Data::DumperData::Dump模块(后者通常产生更漂亮的输出):

use Data::Dump;  # use Data::Dumper;
dd \@Hits;       # print Dumper \@Hits;
Run Code Online (Sandbox Code Playgroud)

我们相处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]
        ];
Run Code Online (Sandbox Code Playgroud)

所以我说解决方案是声明你的变量.具体来说,我们需要词汇变量.这些变量仅声明它们的块可见.这使得对代码的推理变得更加容易.我们可以像这样声明一个词法变量:

my $foo = 123;
Run Code Online (Sandbox Code Playgroud)

当我们有一个像循环

my @Hits;
for my $i  (0 .. 9) {
  my @Space;
  push @Hits, \@Space;
}
Run Code Online (Sandbox Code Playgroud)

然后每次my执行,我们得到一个新的 @Space.哦,我使用了一个foreach循环,0 .. 9用(词法)$i变量迭代范围.我发现这比你使用的C风格循环更容易理解.

因为@Hits现在的每个元素都是不同的 arrayref,所以我们得到了预期的数据结构.作为Data::Dump输出:

[[], [1], [], [3], [], [5], [], [7], [], []]
Run Code Online (Sandbox Code Playgroud)

当我们现在执行你的循环打印出每个子数组的第一个值时,你可能会对数字之间的空行感到惊讶.这是因为例如第一个arrayref在索引处没有条目0,因此返回特殊undef值.当用作字符串时,这是空字符串.如果您遵循我的建议并执行了此操作use warnings,您还会收到一条消息,指出您正在打印未初始化的值.

我们可以通过测试定义来解决这个问题,否则提供零.从perl5 v10开始,我们可以使用defined-or运算符//(在早期的perls上,||逻辑或必须执行).

for my $i (0 .. 9) {
  my $value = $Hits[$i][0] // 0;
  print "$value\n";
}
Run Code Online (Sandbox Code Playgroud)

我们还可以改进其他一些内容:

  • 我们不必手动创建@Space数组; 当您取消引用数组条目时,Perl会在幕后执行此操作@{ $Hits[$i] }.这称为自动更新.
  • 我们不仅可以遍历范围,还可以遍历数组.这比硬编码索引要好得多.
  • 从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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

0
1
0
3
0
5
0
7
Run Code Online (Sandbox Code Playgroud)

(注意,我们从未在位置8和9处初始化值,因此它们不会显示.我们可以通过迭代切片 来修改它@Hits[0 .. 9].)