Проблема в том, что вы не правильно объявляете свои переменные. Для каждого сценария, вы должен
use strict; use warnings;
Это запрещает общие источники ошибок, предупреждает о ненадежном материале, и заставляет вас правильно объявлять все переменные.
По умолчанию все необъявленные переменные считаются глобальными. Таким образом, в
for($i=0;$i<=9;$i++)
{
@Space =();
push(@Hits,\@Space);
}
@Space
относится к тому же массиву в каждой итерации. Ergo, все десять записей в @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
теперь является различными arrayref, мы получаем ожидаемую структуру данных.Как Data::Dump
выхода:
[[], [1], [], [3], [], [5], [], [7], [], []]
Когда мы теперь выполнить свой цикл, который печатает первое значение каждого суб-массив, то вы можете быть удивлены пустыми линиями между numebers. Это происходит потому, что, например, первый arrayref не имеет записи в индексе 0
и поэтому возвращает специальное значение undef
. При использовании в качестве строки это пустая строка. Если вы следовали моему совету и сделали use warnings
, вы также получите сообщение о том, что вы печатаете неинициализированное значение.
Мы можем решить это путем тестирования на определенность и предоставления нулевого значения в противном случае. Начиная с perl5 v10, мы можем использовать определенный или оператор //
для этого (на ранних perls, ||
логический или должен делать).
for my $i (0 .. 9) {
my $value = $Hits[$i][0] // 0;
print "$value\n";
}
Есть несколько других битов мы можем улучшить:
- Мы не должны создавать вручную
@Space
массивы; Perl делает это за кулисами, когда вы разыгрываете запись в виде массива, например @{ $Hits[$i] }
. Это называется автовивизация.
- Мы можем не только перебирать диапазоны, но и массивы. Это намного лучше, чем индексы жесткого кодирования.
- Начиная с версии 10, вы можете использовать функцию
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]
.)