http://qs321.pair.com?node_id=660756

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

I have a hash having keys values pair as follow:
%myhash = { 1 => 'a', 2=> 'b', 3=> 'a', 4=>'c'}

Now i want to get the keys where the value is 'a'.
How can i do this?
  • Comment on How to get Keys from hash having same value?

Replies are listed 'Best First'.
Re: How to get Keys from hash having same value?
by ysth (Canon) on Jan 07, 2008 at 05:55 UTC
Re: How to get Keys from hash having same value?
by merlyn (Sage) on Jan 07, 2008 at 06:06 UTC
    Oops:
    %myhash = { 1 => 'a', 2=> 'b', 3=> 'a', 4=>'c'}
    isn't gonna work. You're creating a hashref (resulting in a single scalar) on the right, but assigning it to a hash (wanting a list) on the left. You should be consistent.
Re: How to get Keys from hash having same value?
by McDarren (Abbot) on Jan 07, 2008 at 05:54 UTC
    Iterate through the keys of your hash, and look at the value of each one in turn.
    for (keys %myhash) { print "$_ eq a\n" if $myhash{$_} eq 'a'; }
      Or, to avoid the extra hash lookups, iterate over key-value pairs using each.
      my @as = (); while (my ($key, $value) = each %myhash){ push @as, $key if $value eq 'a'; }

      Update:

      Is there a monk among us who can shorten this into a one-liner, similar to the grep keys examples we have seen?

      It seems that each does not combine nicely with grep, map and their ilk.

        Voilà:
        %newhash = reverse do { my $hash = reverse %myhash; %hash };

        To get the keys only (which are the values in the reversed hash:

        @unique_keys = do { my $hash = reverse %myhash; values %hash };

        update: oops, got it all wrong. It' about getting all keys where duplicate values are found. As a single statement, formatted for readability

        %myhash = (1 => 'a', 2=> 'b', 3=> 'a', 4=>'c',5 => 'b', 6 => 'a'); @k = do { my %s; map { my $v=$_; grep { $myhash{$_} eq $v} keys %myhash } grep {$s{$_}++==1} values %myhash }; print "$_ => $myhash{$_}\n" for @k; __END__ 6 => a 1 => a 3 => a 2 => b 5 => b

        Ah well. Readability... ;-)

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        I tried doing that, It is working.
        use Data::Dumper; %myhash = ( 1 => 'a', 2=> 'b', 3=> 'a', 4=>'c', 5 => 'a', 6 => 'a', 7 +=>'b'); %newhash = map { ($_,$myhash{$_}) } grep { $myhash{$_} eq 'a'; } keys + %myhash ; print Dumper \%newhash;
Re: How to get Keys from hash having same value?
by NetWallah (Canon) on Jan 07, 2008 at 07:08 UTC
    If you are going to be making this query frequently, you may want to pre-build a "reverse lookup" hash:
    my %h1 = qw (1 a 2 b 3 a 4 c); my %h2; #Used for Value-to-key lookup push @{$h2{$h1{$_}}},$_ for keys %h1; # Builds the reverse hash print join( ",",@{$h2{a}}); # Lookup and print all keys in h1 that +contain the value 'a' # Prints: 1,3

         "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

Re: How to get Keys from hash having same value?
by Punitha (Priest) on Jan 07, 2008 at 06:10 UTC

    Hi isha,

    If you want to manipulate the simple hash, then your hash will be like this,

    my %myhash = ( 1 => 'a', 2=> 'b', 3=> 'a', 4=>'c');

    To manipulate this simple hash, you can do like

    use strict; my %myhash = ( 1 => 'a', 2=> 'b', 3=> 'a', 4=>'c'); for my $key (keys %myhash){ if($myhash{$key} eq 'a'){ print "KEY:$key\n"; } }

    But you created the hash as

    my %myhash = { 1 => 'a', 2=> 'b', 3=> 'a', 4=>'c'};

    which is anonymous hash reference. To manipulate this hash reference, then you can do like

    use strict; my $myhash = { 1 => 'a', 2=> 'b', 3=> 'a', 4=>'c'}; for my $key (keys %{$myhash}){ if(${$myhash}{$key} eq 'a'){ print "KEY:$key\n"; } }

    Punitha

Re: How to get Keys from hash having same value?
by ikegami (Patriarch) on Jan 07, 2008 at 09:57 UTC
    If you're going to do this repeatedly (e.g. first find all the keys with value 'a', then find all keys with value 'b', etc.), then it might help to create a hash that maps the values to keys.
    my %val_by_key = ( 1 => 'a', 2 => 'b', 3 => 'a', 4 => 'c', ); my %keys_by_val foreach my $k (keys %vals_by_key) { my $v = $vals_by_key{$k}; push @{ $keys_by_val{$v} }, $k; } # a: 1, 3 print('a: ', join(', ', @{$keys_by_val{'a'}}), "\n"); # a: 1, 3 # b: 2 # c: 4 foreach my $v (keys %keys_by_val) { print("$v: ", join(', ', @{$keys_by_val{$v}}), "\n"); }
Re: How to get Keys from hash having same value?
by ambrus (Abbot) on Jan 08, 2008 at 07:40 UTC