Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obtaining a slice through an array of hash references in Perl

I have a Perl-related question, concerning complex data structures. I am running version 5.8.8 of Perl on a Linux (Centos v5) server, hosting Apache. I am interrogating a MS-SQL database. I am using the "DBI" Perl module.

I have a table of results from an SQL query, encoded as a reference to an array of hash references. So each row in the table is an array element containing a hash reference, obtained using the "fetchrow_hashref" command of the DBI module. The keys of each hash correspond to the column headings and the values corresponding to a particular cell in the table under that column heading.

What I would like to do is to obtain an array of column data. There appear to be some methods described in the DBI documentation about how to obtain column data, but to me they are a little opaque, and it would be nice to know in general how to obtain a slice through an array of hash references as an exercise in understanding how perl referencing / dereferencing works.

So, basically, given this:

my %datarow1 = {"firstname"=> "dave", "bar"=>"smith"};
my %datarow2 = {"firstname"=> "john", "bar"=>"doe"};
my %datarow3 = {"firstname"=> "kim", "bar"=>"kardashian"};

Referenced like this:

my @rows = (\%datarow1, \%datarow2, \%datarow3);
my $rowsref=\@rows;

How do I get this array?:

("dave", "john", "kim")

I've tried this:

my @columndata=@$rowsref->[0]{"firstname"}

but this only gets me the first cell in the column (i.e. an array containing the one element "dave"). There must be an elegant way of doing this in one line - if on of you perl gurus could help me out, I'd appreciate it hugely.

Thanks

C J

like image 271
Campbell Reid Avatar asked Dec 25 '22 09:12

Campbell Reid


2 Answers

A few things to start:

This is not how you define a Hash:

my %datarow1 = {"firstname"=> "dave", "bar"=>"smith"};

this line of code assigns a Hash reference to a Hash, which results in a structure like this:

( 'HASH(0x7f4ef0545e18)' => undef )

probably not what you wanted.

To define your hashes correctly replace the curly braces with parentheses:

my %datarow1 = ("firstname"=> "dave", "bar"=>"smith");

Always enable strict mode and warnings:

use strict;
use warnings; 

this would have caught the mistake of assigned a reference to a Hash.

--

Now, the real question is "How do I extract a specific key from Hash references held in an array?"

and the answer is exactly the same way as if the Hash references were not in an array:

my $h_ref = { a => b };
# get key 'a'
my $a = $h_ref->{a}; 

the only difference is that you need to apply this operation over an array. Applying operations over arrays is the purpose of the map builtin:

use strict;
use warnings; 

my %datarow1 = ("firstname"=> "dave", "bar"=>"smith");
my %datarow2 = ("firstname"=> "john", "bar"=>"doe");
my %datarow3 = ("firstname"=> "kim", "bar"=>"kardashian");

my @rows = (\%datarow1, \%datarow2, \%datarow3);
my $rowsref=\@rows;
my @firstnames = map { $_->{firstname} } @$rowsref; 
# dave john kim
like image 82
Hunter McMillen Avatar answered Dec 27 '22 12:12

Hunter McMillen


If you've used use strict; use warnings; you'd get:

Reference found where even-sized list expected at "script" "line"

You want to populate a hash, use:

my %datarow1 = ("firstname"=> "dave", "bar"=>"smith");

Note the parenthesis instead of curly brackets

Then, for printing the firstname, use:

my @columndata = map {$_->{"firstname"}}  @$rowsref;
say Dumper\@columndata;
like image 45
Toto Avatar answered Dec 27 '22 12:12

Toto