The "direct", although inefficient approach would be to inspect the arrays and look for the values, for example using grep:

for my $key (keys %hash) { print "$key\n" if grep {$_ eq "banana"} @{ $hash{$key} }; }

This is inefficient because it searches the entire hash of arrays structure. It would be more efficient if you either structure your data as a hash of hashes from the beginning, or convert it. Then, it's just a matter of hash lookups, which are much faster than grepping an array. Of course, building a second data structure will eat more memory, which could be a problem if the initial data structure is large, but especially for small data structures often the speed gain will outweigh the memory cost.

# convert my %hoh = map { $_ => { map {$_=>1} @{ $hash{$_} } } } keys %hash; # debug: inspect the converted data use Data::Dumper; print Dumper(\%hoh); # lookup my $search = "banana"; for my $key (keys %hoh) { print "$key\n" if $hoh{$key}{$search}; }

Update: Taking this two steps further, you can build an inverse data structure, so that you don't need to do any searching, you just look up based on the string (banana). This first example applies only (!) if you know that all the values across all of the arrays are unique:

# build inverse hash, if all values are unique my %inverse_hash; for my $key (keys %hash) { for my $val (@{ $hash{$key} }) { $inverse_hash{$val} = $key; } } # debug: inspect the converted data print Dumper(\%inverse_hash); # lookup is simple! print $inverse_hash{banana}, "\n";

If there can be duplicate values across the arrays, then an "inverse" hash of arrays would be more appropriate:

# convert to "inverse" hash of arrays (in two steps) my %hoa; # first, build a hash of hashes # (this eliminates duplicates at both levels) for my $key (keys %hash) { for my $val (@{ $hash{$key} }) { $hoa{$val}{$key}++; } } # then, convert the second level of hashes to arrays for my $vals (values %hoa) { $vals = [sort keys %$vals]; } # debug: inspect the converted data print Dumper(\%hoa); # lookup print join(', ', @{ $hoa{banana} } ), "\n"

Update 2: In the last example, if you're looking up keys that may not exist, you could use the //[] trick that tybalt89 showed, as in @{ $hoa{banana} // [] }, or you could first check for the existence of the key (e.g. if (exists $hoa{banana})). (Also, in the text above I added a bit of clarification/explanation, e.g. because both the initial data structure and my final example are a hash of arrays.)


In reply to Re: Using an element in a Hash of Arrays to access the key (updated x2) by haukex
in thread Using an element in a Hash of Arrays to access the key by orangepeel1

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.