Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Checking a hash for two matching values.

by walkingthecow (Friar)
on Sep 17, 2013 at 04:10 UTC ( [id://1054383]=perlquestion: print w/replies, xml ) Need Help??

walkingthecow has asked for the wisdom of the Perl Monks concerning the following question:

I have an array of hashes, and I am trying to return from this array of hashes all hashes that contain two values, say cat and dog.
Here's the line I have:
my @results = grep { grep { $_ =~ /(?=.*cat)(?=.*dog)/i } values %$_ } + @{ $lines };
Now, I know for a fact that there are hashes in this array of hashes that contain both cat and dog, but for some reason nothing is being returned.

UPDATE: Thanks to help from tye in the Chatterbox, I have figured out what to do here. My goal was to translate from boolean (AND, OR, NOT) to Regex, then match that against the values in an AoHes. Here's how it worked:
grep { grep /cat/, grep /dog/, values %h } grep { grep /cat/, values %$_ } grep { grep /dog/, values %$_ } @aoh
Both solutions worked, though I am going with the first one.

Replies are listed 'Best First'.
Re: Checking a hash for two matching values.
by moritz (Cardinal) on Sep 17, 2013 at 04:34 UTC

    The regex only works if the hash contains cat and dog in the same value, but judging from the description, that's not what you want.

    Instead of trying to be too clever, I'd use something like this:

    use 5.014; use warnings; my @hashes = ( { bla => 'cat', blubb => 'dog' }, { only => 'cat' }, { just => 'dog' }, ); sub hr_contains_cat_and_dog { my $hr = shift; my ($has_cat, $has_dog); for (values %$hr) { $has_cat = 1 if /cat/i; $has_dog = 1 if /dog/i; } return $has_cat && $has_dog; } my @result = grep hr_contains_cat_and_dog($_), @hashes; use Data::Dumper; print Dumper \@result; __END__ $VAR1 = [ { 'bla' => 'cat', 'blubb' => 'dog' } ];
Re: Checking a hash for two matching values.
by kcott (Archbishop) on Sep 17, 2013 at 04:39 UTC

    G'day walkingthecow,

    Your posted solution seems overly complicated. Some test data would have been useful. Here's how I might have tackled this:

    $ perl -Mstrict -Mwarnings -e ' use List::MoreUtils qw{uniq}; use Data::Dumper; my @pets = ( { a => "cat", b => "dog" }, { c => "dog", d => "cat" }, { e => "dog" }, { f => "cat" }, { g => "goldfish" }, { h => "cat", i => "cat" }, { j => "cat", k => "cat", l => "dog", m => "dog" }, ); my @cat_and_dog; for (@pets) { push @cat_and_dog, $_ if 2 == grep { /^(?:cat|dog)$/ } uniq va +lues %$_; } print Dumper \@cat_and_dog; ' $VAR1 = [ { 'b' => 'dog', 'a' => 'cat' }, { 'd' => 'cat', 'c' => 'dog' }, { 'j' => 'cat', 'k' => 'cat', 'l' => 'dog', 'm' => 'dog' } ];

    -- Ken

        Yes, I had considered adding other test data: "cats", "dogs", "catalogue", "raining cats and dogs", etc. I wasn't really sure what walkingthecow wanted, which prompted the "Some test data would have been useful." comment.

        -- Ken

Re: Checking a hash for two matching values.
by NetWallah (Canon) on Sep 17, 2013 at 05:07 UTC
    Arguably more readable than those above ... (IMHO, code matches problem description closer)
    my @found= grep { my %r = reverse %$_; exists $r{cat} && exists $r{d +og}} @pets;

                 My goal ... to kill off the slow brain cells that are holding me back from synergizing my knowledge of vertically integrated mobile platforms in local cloud-based content management system datafication.

        It's easy enough to add case insensitivity to NetWallah's code with fc or lc.

        For v5.16 or newer:

        use v5.16; ... my @found= grep { my %r = reverse map fc, %$_; exists $r{cat} && exists $r{dog} } @pets;
        For older versions as well:
        my @found= grep { my %r = reverse map lc, %$_; exists $r{cat} && exists $r{dog} } @pets;

        Hmm - I did not notice any hints of requiring case-insensitivity, but in any case, that requirement is easily accommodated in my code by adding a "map {lc}" .
        my @found= grep { my %r = map{lc} reverse %$_; exists $r{cat} && exis +ts $r{dog}} @pets;

                     My goal ... to kill off the slow brain cells that are holding me back from synergizing my knowledge of vertically integrated mobile platforms in local cloud-based content management system datafication.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1054383]
Approved by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (7)
As of 2024-03-28 18:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found