Добавление хеша в массив - PullRequest
21 голосов
/ 27 ноября 2011

У меня есть такой массив,

@switch_ports = ()

и затем хотите добавить 50 экземпляров этого хэша в массив switch_ports

%port = (data1 => 0, data2 => 0, changed => 0)

однако, если я добавлю свой хэш в массив

push(@switch_ports, %port)

но если я напечатаю @switch_ports Я просто вижу

data10data20changed0

так что, кажется, они добавляются в массив (присоединяются к ним) и если я попытаюсь зациклить массив и напечатать ключи, он также завершится ошибкой.

Мне кажется, я отстал от того, что так сильно ударился головой о стол.

1 - Можете ли вы сохранить хэш в массиве?

2 - Можете ли вы иметь массив хэшей?

Пытаясь получить ...

switchports
    0
        data1
        data2
        changed
    1
        data1
        ....

Таким образом,

foreach $port (@switchport) {
    print $port['data1']
}

вернет все данные1 для всех хэшей в массиве.

Да, я не в Perl

Ответы [ 4 ]

38 голосов
/ 27 ноября 2011

В Perl члены массива и хеша должны иметь одно значение.До Perl 5.0 не было (простого) способа сделать то, что вы хотите.

Однако в Perl 5 теперь можно использовать ссылку на ваш хэш.Ссылка - это просто область памяти, где хранится элемент.Чтобы получить ссылку, вы должны поставить обратную косую черту перед переменной:

use feature qw(say);

my $foo = "bar";
say $foo;    #prints "bar"
say \$foo;   #prints SCALAR(0x7fad01029070) or something like that

Таким образом:

my @switch_ports = ();
my %port = ( data1 => 0, data2 => 0, changed => 0 );
my $port_ref = \%port;

push( @switch_ports, $port_ref );

И вам не нужно создавать $port_ref:

my @switch_ports = ();
my %port = ( data1 => 0, data2 => 0, changed => 0 );

push( @switch_ports, \%port );

Чтобы получить фактическое значение ссылки, просто поставьте символ на лицевой стороне:

#Remember: This is a REFERENCE to the hash and not the hash itself
$port_ref = $switch_ports[0];
%port = %{$port_ref};      #Dereferences the reference $port_ref;

print "$port{data1}  $port{data2}  $port{changed}\n";

Еще один ярлык:

%port = %{$port[0]};   #Dereference in a single step
print "$port{data1}  $port{data2}  $port{changed}\n";

Или, еще короче,разыменование по мере продвижения:

print ${$port[0]}{data1} . " " . ${$port[0]}{data2} . " " . ${$port[0]}{changed} . "\n";

И немного синтаксического подсластителя.Это означает то же самое, но легче читать:

print $port[0]->{data1} . " " . $port[0]->{data2} . " " . $port[0]->{changed} . "\n";

Взгляните на Perldoc perlreftut и perlref .Первый - учебник.

9 голосов
/ 27 ноября 2011

Когда вы пытаетесь:

%port = (data1 => 0, data2 => 0, changed => 0);
push @switch_ports, %port;

Что действительно происходит:

push @switch_ports, "data1", 0, "data2", 0, "changed", 0;

Поскольку массивы и хэши автоматически разбиваются на их элементы при использовании в спискеcontext.

Когда вы хотите создать 50 экземпляров хеша, не рекомендуется использовать ссылку на существующий хеш, как предлагали другие, поскольку это создаст только 50 различных ссылок на тот же хэш.Который вылетит и сгорит по понятным причинам.

Вам нужно что-то вроде:

push @array, { data1 => 0, data2 => 0, changed => 0 } for 1 .. 50;

, который добавит 50 уникальных анонимных хешей в массив.Скобки обозначают создание анонимного хэша и возвращают скалярную ссылку на него.

ETA: Ваш пример доступа к этим данным неверен.

foreach $port (@switchport) {
    print $port['data1'];    # will use @port, not $port
}

Использование нижнего индекса скалярной переменной будет пытаться получить доступ к массиву в этом пространстве имен, а не к скаляру.В perl допустимо иметь две отдельные переменные $port и @port.Скобки используются для массивов, а не хэшей.При использовании ссылок также необходимо использовать оператор стрелки: $port->{data1}.Отсюда:

for my $port (@switchport) {
    print $port->{data1};
}
4 голосов
/ 18 октября 2013

Чтобы упростить для тех, кто использует этот вопрос, чтобы найти общий подход - как в заголовке вопроса.Тема Mysql:

my @my_hashes = ();
my @$rows = ... # Initialize. Mysql SELECT query results, for example.

if( @$rows ) {
    foreach $row ( @$rows ) { # Every row to hash, every hash to an array.
        push @my_hashes, { 
            id => $row->{ id }, 
            name => $row->{ name }, 
            value => $row->{ value }, 
        };
    }
}

Для зацикливания и распечатки:

for my $i ( 0 .. $#my_hashes ) {
    print "$my_hashes[$i]{ id }\n ";
    print "$my_hashes[$i]{ name }\n ";
    print "$my_hashes[$i]{ value }\n ";
}

или

for my $i ( 0 .. $#my_hashes ) {
for my $type ( keys %{ $my_hashes[$i] } ) {
     print "$type=$my_hashes[$i]{$type} ";
}

}

4 голосов
/ 27 ноября 2011

Вы можете сохранить ссылку на хеш в массиве:

push @switchport, \%port; # stores a reference to your existing hash

или

push @switchport, { %port }; # clones the hash so it can be updated separately

Затем выполните итерации, скажем,

foreach my $port (@switchport) {
    print $port->{'data1'}; # or $$port{'data1'}
}

См. man perlref.

...