Search code examples
arraysperlmultidimensional-arrayhashtable

Adding a hash to an array


I have an array like so:

@switch_ports = ()

and then want to add 50 instances of this hash, to the switch_ports array.

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

However, if I push my hash to the array:

push(@switch_ports, %port)

and I do print @switch_ports, I just see:

data10data20changed0

so it just seems to be adding them to the array, (joining them) and if I try and loop the array and print the keys, it also fails.

  1. Can you store a hash in an array?

  2. Can you have an array of hashes?

I'm trying to get this:

switchports
    0
        data1
        data2
        changed
    1
        data1
        ....

thus:

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

would return all of the data1 for all of the hashes in the array.


Solution

  • In Perl, array and hash members must be a single value. Before Perl 5.0, there was no (easy) way to do what you want.

    However, in Perl 5 you can now use a reference to your hash. A reference is simply the memory location where the item is being stored. To get a reference, you put a backslash in front of the variable:

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

    Thus:

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

    And, you don't have to create $port_ref:

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

    To get the actual value of the reference, simply put the symbol back on front:

    #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";
    

    Another shortcut:

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

    Or, even shorter, dereferencing as you go along:

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

    And a little syntactic sweetener. It means the same, but is easier to read:

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

    Take a look at Perldoc's perlreftut and perlref. The first one is a tutorial.