Perl: правильно печатать массив массивов (разыменование)
Эй, товарищи монахи Perl,
Я все еще оборачиваюсь вокруг того, как правильно разыскивать. (Я прочитал подобные посты до публикации, но, к сожалению, все еще немного не в себе).
У меня есть следующий массив, который внутренне состоит из двух массивов. (Кстати, я использую строгие и предупреждающие прагмы.)
use strict; use warnings;
my @a1; my @a2;
где:
@a1 = ( "1MB", "2MB", ... )
а также..
@a2 = ( "/home", "/home/debug", ... )
Оба @a1 & @a2 являются массивами, которые содержат 51 строку. Итак, я заполняю их во второй массив.
my @b;
push (@b, [ @a1, @a2 ]);
Тем не менее, когда я пытаюсь распечатать результаты @b:
sub newl { print "\n"; print "\n"; }
my $an1; my @an1;
$an1 = $#a1;
@an1 = ( 0, 1..$an1 );
for my $i (@an1) { print @b[$i]; &newl; }
Я вижу ссылки на массивы:
ARRAY(0x81c0a10)
.
ARRAY(0x81c0a50)
.
.
.
Как правильно распечатать этот массив? Я знаю, что мне нужно разыменовать массив, я не уверен, как это сделать. Я попытался заполнить мой массив так:
push (@b, [ \@a1, \@a2 ]);
Который дает те же результаты. Я также попробовал:
for my $i (@an1) { print @{$b[$i]}; &newl; }
К сожалению, какие ошибки из-за наличия 0 в качестве ссылки на массив?
Can't use string ("0") as an ARRAY ref while "strict refs" in use at p_disk_ex6.pl line 42.
Любые предложения с благодарностью!
3 ответа
Краткий пример программы, которая может вам помочь:
use strict;
use warnings;
my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);
my @b = (\@a1, \@a2);
# equivalent long version:
# my @b = ();
# $b[0] = \@a1;
# $b[1] = \@a2;
for (my $i = 0; $i <= $#a2; $i++) {
print "a1[$i]: $b[0][$i]\n";
print "a2[$i]: $b[1][$i]\n";
print "\n";
}
В вашем примере вы вставили аномальный массив ref [] в @b. Следовательно, $b[0] содержит arrayref.
my @b;
push (@b, [ \@a1, \@a2 ]);
# this corresponds to:
# $b[0][0] = \@a1;
# $b[0][1] = \@a2;
В примере, где вы написали [@a1, @a2], вы создавали array_ref, который содержал объединенные массивы @ a1 и @a2 (сначала все элементы @ a1, а затем все элементы @a2):
my @b;
push(@b , [@a1, @a2]);
# $b[0] = ['1MB' , '2MB', '10Mb', '7MB', '/foo', '/bar', '/flub', '/blub']
Даже просто это также работает
use strict;
use warnings;
my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);
my @b = (@a1, @a2);
print "@b";
Если вам нужно общее решение, которое не предполагает, сколько элементов имеется в каждом из под-массивов, и которое также допускает произвольные уровни вложенности, лучше использовать пакеты, которые кто-то уже написал для отображения рекурсивных данных. структур. Особенно распространенным является YAML, который вы можете установить, если у вас его еще нет, запустив cpan:
$ cpan
Terminal does not support AddHistory.
cpan shell -- CPAN exploration and modules installation (v1.9800)
Enter 'h' for help.
cpan[1]> install YAML
Тогда вы можете легко отобразить произвольные структуры данных. Для демонстрации на простом примере:
use YAML;
my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);
my @b = (\@a1, \@a2);
print Dump(\@b);
результаты в выводе
---
-
- 1MB
- 2MB
- 10MB
- 7MB
-
- /foo
- /bar
- /flub
- /blub
Для немного более сложного примера
my @b = (\@a1, \@a2,
{ a => 0, b => 1 } );
дает
---
-
- 1MB
- 2MB
- 10MB
- 7MB
-
- /foo
- /bar
- /flub
- /blub
- a: 0
b: 1
Чтобы прочитать это, три символа "-" в столбце 1 указывают массив с тремя элементами. Первые два элемента имеют четыре подэлемента каждый (строки с "-" в столбце 3). Третий внешний элемент - это ссылка на хеш, поскольку он состоит из пар "ключ: значение".
Приятной особенностью YAML является то, что вы можете использовать ее для выгрузки любой рекурсивной структуры данных в файл, кроме тех, у которых есть ссылки на подпрограммы, а затем прочитать ее позже, используя Load.
Если вам действительно нужно развернуть свою собственную процедуру отображения, это, безусловно, возможно, но вам будет гораздо легче, если вы напишите ее рекурсивно. Вы можете проверить, является ли ваш аргумент ссылкой на массив или ссылкой на хеш (или скалярной ссылкой), используя ref:
my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);
my @b = (\@a1, \@a2,
{ a => 0, b => 1 } );
print_recursive(\@b);
print "\n";
sub print_recursive {
my ($obj) = @_;
if (ref($obj) eq 'ARRAY') {
print "[ ";
for (my $i=0; $i < @$obj; $i++) {
print_recursive($obj->[$i]);
print ", " if $i < $#$obj;
}
print " ]";
}
elsif (ref($obj) eq 'HASH') {
print "{ ";
my @keys = sort keys %$obj;
for (my $i=0; $i < @keys; $i++) {
print "$keys[$i] => ";
print_recursive($obj->{$keys[$i]});
print ", " if $i < $#keys;
}
print " }";
}
else {
print $obj;
}
}
который производит вывод
[ [ 1MB, 2MB, 10MB, 7MB ], [ /foo, /bar, /flub, /blub ], { a => 0, b => 1 } ]
Я не писал свой пример кода, чтобы беспокоиться о симпатичной печати, и при этом он не обрабатывает скалярные, подпрограммные или благословенные ссылки на объекты, но он должен дать вам представление о том, как вы можете написать довольно общий рекурсивный дампер структуры данных.