How to get hashes out of arrays in Perl?

11,720

Solution 1

The nested data structure contains a hash reference, not a hash.

# Will work (the -> dereferences the reference)
$row = $records[$index];
print "This will work: ", $row->{firstName}, "\n";

# This will also work, by promoting the hash reference into a hash
%row = %{ $records[$index] };
print "This will work: ", $row{firstName}, "\n";

If you're ever presented with a deep Perl data structure, you may profit from printing it using Data::Dumper to print it into human-readable (and Perl-parsable) form.

Solution 2

The array of hashes doesn't actually contain hashes, but rather an references to a hash. This line:

%row = $records[$index];

assigns %row with one entry. The key is the scalar:

   {'id' => 1, 'firstName' => 'Jim'},

Which is a reference to the hash, while the value is blank.

What you really want to do is this:

$row = $records[$index];
$row->{'firstName'};

or else:

$row = %{$records[$index];}
$row{'firstName'};

Solution 3

Others have commented on hashes vs hashrefs. One other thing that I feel should be mentioned is your DBQuery function - it seems you're trying to do something that's already built into the DBI? If I understand your question correctly, you're trying to replicate something like selectall_arrayref:

This utility method combines "prepare", "execute" and "fetchall_arrayref" into a single call. It returns a reference to an array containing a reference to an array (or hash, see below) for each row of data fetched.

Solution 4

To add to the lovely answers above, let me add that you should always, always, always (yes, three "always"es) use "use warnings" at the top of your code. If you had done so, you would have gotten the warning "Reference found where even-sized list expected at -e line 1."

Solution 5

what you actually have in your array is a hashref, not a hash. If you don't understand this concept, its probably worth reading the perlref documentation.

to get the hash you need to do

my %hash = %{@records[$index]};

Eg.

my @records = (
     {'id' => 1, 'firstName' => 'Jim'}, 
     {'id' => 2, 'firstName' => 'Joe'}
  );

  my %hash = %{$records[1]};

  print $hash{id}."\n";

Although. I'm not sure why you would want to do this, unless its for academic purposes. Otherwise, I'd recommend either fetchall_hashref/fetchall_arrayref in the DBI module or using something like Class::DBI.

Share:
11,720
Angry Dan
Author by

Angry Dan

web/software developer, .NET, C#, WPF, PHP, software trainer, English teacher, have philosophy degree, love languages, run marathons my tweets: http://www.twitter.com/edward_tanguay my runs: http://www.tanguay.info/run my code: http://www.tanguay.info/web my publications: PHP 5.3 training video (8 hours, video2brain) my projects: http://www.tanguay.info

Updated on July 14, 2022

Comments

  • Angry Dan
    Angry Dan almost 2 years

    I want to write a little "DBQuery" function in perl so I can have one-liners which send an SQL statement and receive back and an array of hashes, i.e. a recordset. However, I'm running into an issue with Perl syntax (and probably some odd pointer/reference issue) which is preventing me from packing out the information from the hash that I'm getting from the database. The sample code below demonstrates the issue.

    I can get the data "Jim" out of a hash inside an array with this syntax:

    print $records[$index]{'firstName'}
    

    returns "Jim"

    but if I copy the hash record in the array to its own hash variable first, then I strangely can't access the data anymore in that hash:

    
        %row = $records[$index];
        $row{'firstName'};
    

    returns "" (blank)

    Here is the full sample code showing the problem. Any help is appreciated:

    
    my @records = (
       {'id' => 1, 'firstName' => 'Jim'},
       {'id' => 2, 'firstName' => 'Joe'}
    );
    my @records2 = ();
    
    $numberOfRecords = scalar(@records);
    print "number of records: " . $numberOfRecords . "\n";
    for(my $index=0; $index < $numberOfRecords; $index++) {
    
       #works
       print 'you can print the records like this: ' . $records[$index]{'firstName'} . "\n";
    
       #does NOT work
       %row = $records[$index];
       print 'but not like this: ' . $row{'firstName'} . "\n";
    
    } 
    
  • daxsorbito
    daxsorbito over 15 years
    If you ever need to explictly dereference a reference then %{$row} will work, which can be useful sometimes to ensure you're passing the right thing to the right sort of thing.
  • Peter Stuifzand
    Peter Stuifzand over 15 years
    That last bit of code makes no sense. It should be something like: %row=%{$records[$index]}; print $row{'firstName'};
  • Francisco Zarabozo
    Francisco Zarabozo almost 10 years
    @records[$index] better written as $records[$index]
  • Shravya Boggarapu
    Shravya Boggarapu over 7 years
    my $h_ref = $arrayOfValidImages[$i]; (Is a valid array of hash refs and valid index) my %image_info = %{$h_ref}; (This very next line gives an error: "Can't use an undefined value as a HASH reference at <line number>". Any idea?