Home > Enterprise >  What's the most efficient way to check multiple hash references in perl
What's the most efficient way to check multiple hash references in perl

Time:11-08

I have a multidimensional data structure for tracking different characteristics of files I am comparing and merging data for. The structure is set up as such:

$cumulative{$slice} = {
    DATA    => $data,
    META    => $got_meta,
    RECOVER => $recover,
    DISPO   => $dispo,
    DIR     => $dir,
};

All of the keys, save DIR (which is just a simple string), are references to hashes, or arrays. I would like to have a simple search for KEYS that match "BASE" for the value DIR points to for each of the $slice keys. My initial thought was to use grep, but I'm not sure how to do that. I thought something like this would be ok:

my (@base_slices) = grep { $cumulative{$_}->{DIR} eq "BASE" } @{$cumulative{$_}};

I was wrong. Is there a way to do this without a loop, or is that pretty much the only way to check those values? Thanks!

Edit: Thanks to Ikegami for answering succinctly, even without my fully representing the outcome of the search. I have changed the question a little bit to more clearly explain the issue I was having.

CodePudding user response:

The use of @{$cummulative{$_}} indicates that $slice, for which $_ presumably stands for, would be an arrayref. However, having that for a key in a hash is no good -- it would get stringified and that string literal would have nothing to do with the $slice's underlying array.

But if $slice stands for a value out of a set that can be retrieved at will then you only need to feed that list to the grep shown in the question

my @base_slices = grep { $cumululative{$_}{DIR} eq 'BASE' } @slice_vals; 

or

my @base_slices = 
    grep { $cumululative{$_}{DIR} eq 'BASE' } 
    map { calculate_slice_values($_) } 
    LIST-OF-INPUTS; 

That calculate_slice_values() stands for the way $slice values are acquired dynamically.

There is no need for a dereferencing arrow for the key DIR (a syntax convenience), and no need for parenthesis around @base_slices since having an array already provides the needed list context.

Please clarify what $slice is meant to be and I'll update.

CodePudding user response:

This is wrong:

@{$cumulative{$slice}}

It gets the value of the array referenced by $cumulative{$slice}. But $cumulative{$slice} is not a reference to an array; it's a reference to a hash. This expression makes no sense, as results in the error

Not an ARRAY reference

What would be correct? Well, it's not quite clear what you want.

Maybe you want the keys of the elements of %cumulative whose DIR attribute equal BASE.

my @matching_keys =                                # 3. Save the results.
   grep { $cumulative{ $_ }->{ DIR } eq "BASE" }   # 2. Filter them.
      keys( %cumulative );                         # 1. Get the keys.

(The -> is optional between indexes, so $cumulative{ $_ }{ DIR } is also fine.)

Maybe you don't need the keys. Maybe you want the values of the elements of %cumulative whose DIR attribute equal BASE.

my @matching_values =                              # 3. Save the results.
   grep { $_->{ DIR } eq "BASE" }                  # 2. Filter them.
      values( %cumulative );                       # 1. Get the values.
  • Related