Home > Enterprise >  Array of Hashrefs: How to access based on hashref "column" values
Array of Hashrefs: How to access based on hashref "column" values

Time:12-22

I have an array of hashrefs built from a database using fethrow_hashref(). The data structure is built like so:

while (my $ref = $sth->fetchrow_hashref()) {
    push @lines, $ref;
}

I sort the data in the query by program name ascending, so all of the references in the array are still in alphabetical order. Then, I go through each hash and find the value that is numerically equal to a '1'. I then take the caolumn name, and store it to compare to the rest of the hashrefs with that program name to ensure they all have a '1' in the same column.

my $pgm = "";
my $met_lvl = "";
my @devs = ();
my %errors = ();
my $error = "";
foreach my $line_ref (@lines) {
    if ($pgm ne $line_ref->{"PROGRAM"}) {
        if (@devs && $error) {
            # print " Different number metal layers for $pgm: @devs \n";
            $error = "";
        }
        @devs = ();
        $pgm = $line_ref->{"PROGRAM"};
        ($met_lvl) = grep { $line_ref->{$_} == 1 } keys(%$line_ref);
        push @devs, $line_ref->{"DEVICE"};
    } elsif ($pgm eq $line_ref->{"PROGRAM"}) {
        push @devs, $line_ref->{"DEVICE"};
        my ($met_chk ) = grep { $line_ref->{$_} == 1 } keys(%$line_ref);
        if ($met_chk ne $met_lvl) {
            $errors{$line_ref->{"PROGRAM"}} = $line_ref->{"PROGRAM"};
            $error = "YUP";
        }
    }
}

I'd like to be able to access the hashrefs individually, based on matching column names from the database. How can I access the hashrefs with "TEST" values for "PROGRAM" keys? I used Data::Dumper to provide an example of a few of the hashrefs I'd like to access based on "PROGRAM" value:

            'PLM' => undef,
            'SLM' => undef,
            'QLM' => undef,
            'DEVICE' => 'DEV1',
            'TLM' => '1',
            'DLM' => undef,
            'ROUTING' => 'NORMAL',
            'PROGRAM' => 'TEST'
          };
$VAR455 = {
            'PLM' => undef,
            'SLM' => undef,
            'QLM' => undef,
            'DEVICE' => 'DEV2',
            'TLM' => '1',
            'DLM' => undef,
            'ROUTING' => 'NORMAL',
            'PROGRAM' => 'TEST'
          };
$VAR456 = {
            'PLM' => undef,
            'SLM' => undef,
            'QLM' => undef,
            'DEVICE' => 'DEV3',
            'TLM' => '1',
            'DLM' => undef,
            'ROUTING' => 'NON_STANDARD',
            'PROGRAM' => 'EXP'
          };
$VAR457 = {
            'PLM' => undef,
            'SLM' => undef,
            'QLM' => undef,
            'DEVICE' => 'DEV4',
            'TLM' => '1',
            'DLM' => undef,
            'ROUTING' => 'NORMAL',
            'PROGRAM' => 'FINAL'
          };

I'd like to be able to access key values for the hashrefs which contain the same program name. I cannot even begin to figure out what type of operation to use for this. I assume map is the correct way to do it, but dereferencing the "PROGAM" value for each element (hashref) in the array is beyond the scope of my understanding. I hope I was able to define the problem well enough for you guys to be able to help.

Edit: The impetus for wanting to access hashrefs with the same 'PROGRAM" value is to be able to provide an output of selected values to print to a logfile. So, after I compare and find differences between those hashrefs with the same "PROGRAM" value, I want to access them all again, and print out the desired column values to the lofgile.

CodePudding user response:

Looks like you need to process subsets of your data (hashrefs) with the same PROGRAM name.

Then can preprocess your data to build a hash with those names as keys, and arrayrefs (with suitable hashrefs) as values. Then process those groups one at a time.

use warnings;
use strict;
use feature 'say';
use Data::Dumper;  # to print complex data below

... populate @lines with hashrefs as shown in the question ...

# Build hash: ( TEST => [ hashrefs w/ TEST ], EXP => [ hashrefs w/ EXP ], ... )
my %prog_subset;    
for my $hr (@lines) { 
    push @{ $prog_subset{$hr->{PROGRAM}} }, $hr;
}

foreach my $prog (keys %prog_subset) { 
    say "Process hashrefs with PROGRAM being $prog";
    foreach my $hr (@{ $prog_subset{$prog} }) {
        say Dumper $hr;
    }
}

Now %prog_subset contains keys TEST, EXP, FINAL (and whatever other PROGRAM names are in data), each having for value an arrayref of all hashrefs which have that PROGRAM name.

This can be done in other ways, and there are libraries that can help, but this should do it.

CodePudding user response:

OK! I found an example of this with the google machine. I replaced @lines = (); with $lines = [];. This allowed me to change the grep statement to (@found) = grep { $pgm eq $_->{PROGRAM} } @$lines;. Now the returned array is a list of the hashrefs that share the program name I'm looking for. Thanks for the help @zdim!

  • Related