Search code examples
perlhashperl-modulesubroutine

Perl pass hash reference to Subroutine from Foreach loop (Array of Hash)


This may be something very simple for you but i have been trying for it for more than one hour.

Ok.. Here is my code,

@collection = [
{
            'name' => 'Flo',
            'model' => '23423',
            'type' => 'Associate',
            'id' => '1-23928-2392',
            'age' => '23',
},
{
            'name' => 'Flo1',
            'model' => '23424',
            'type' => 'Associate2',
            'id' => '1-23928-23922',
            'age' => '25',
}];

foreach my $row (@collection) {
  $build_status = $self->build_config($row);
}

sub build_config {
    my $self = shift;
    my %collect_rows = @_;
    #my %collect_rows = shift;

    print Dumper %collect_rows; exit;
    exit;
}

Where $row is really an Hash. But when i Print it.. It gives output like below (I am using Dumper),

$VAR1 = 'HASH(0x20a1d68)';

Solution

  • You are confusing references with hashes and arrays.

    An array is declared with:

    my @array = (1, 2, 3);
    

    A hash is declared with:

    my %hash = (1 => 2, 3 => 4);
    

    That's because both hashes and arrays are simply lists (fancy lists, but I digress). The only time you need to use the [] and {} is when you want to use the values contained in the list, or you want to create a reference of either list (more below).

    Note that the => is just a special (ie. fat) comma, that quotes the left-hand side, so although they do the same thing, %h = (a, 1) would break, %h = ("a", 1) works fine, and %h = (a => 1) also works fine because the a gets quoted.

    An array reference is declared as such:

    my $aref = [1, 2, 3];
    

    ...note that you need to put the array reference into a scalar. If you don't and do it like this:

    my @array = [1, 2, 3];
    

    ... the reference is pushed onto the first element of @array, which is probably not what you want.

    A hash reference is declared like this:

    my $href = {a => 1, b => 2};
    

    The only time [] is used on an array (not an aref) is when you're using it to use an element: $array[1];. Likewise with hashes, unless it's a reference, you only use {} to get at a key's value: $hash{a}.

    Now, to fix your problem, you can keep using the references with these changes:

    use warnings;
    use strict;
    
    use Data::Dumper;
    
    # declare an array ref with a list of hrefs
    
    my $collection = [
        {
            'name' => 'Flo',
            ...
        },
        {
            'name' => 'Flo1',
            ...
        }
    ];
    
    # dereference $collection with the "circumfix" operator, @{}
    # ...note that $row will always be an href (see bottom of post)
    
    foreach my $row (@{ $collection }) {
        my $build_status = build_config($row);
        print Dumper $build_status;
    }
    
    sub build_config {
        # shift, as we're only accepting a single param...
        # the $row href
    
        my $collect_rows = shift;
        return $collect_rows;
    }
    

    ...or change it up to use non-refs:

    my @collection = (
        {
            'name' => 'Flo',
            ...
        },
        {
            'name' => 'Flo1',
            ...
        }
    );
    
    foreach my $row (@collection) {
        my $build_status = build_config($row);
    
        # build_config() accepts a single href ($row)
        # and in this case, returns an href as well
    
        print Dumper $build_status;
    }
    
    sub build_config {
        # we've been passed in a single href ($row)
    
        my $row = shift;
    
        # return an href as a scalar
    
        return $row;
    }
    

    I wrote a tutorial on Perl references you may be interested in guide to Perl references. There's also perlreftut.

    One last point... the hashes are declared with {} inside of the array because they are indeed hash references. With multi-dimentional data, only the top level of the structure in Perl can contain multiple values. Everything else underneath must be a single scalar value. Therefore, you can have an array of hashes, but technically and literally, it's an array containing scalars where their value is a pointer (reference) to another structure. The pointer/reference is a single value.