Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Selecting particular key-value pairs in hashes

by kiat (Vicar)
on Sep 18, 2004 at 02:49 UTC ( #391933=perlquestion: print w/replies, xml ) Need Help??
kiat has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,

I've a hash as follows:

my %hash = ( '1_277' => 'one', '2_644' => 'some value', 'preview' => 'yes', 'page' => '10', '4_333' => 'done', 'repeat' => 'no' );
I'm looking for a way to get to those key-value pairs where the key has the pattern /\d+_\d+/. In order words, I would like to modify %hash so that it becomes:

%hash = ( '1_277' => 'one', '2_644' => 'some value', '4_333' => 'done', }
How do I do that?

Many thanks in anticipation :)

Replies are listed 'Best First'.
•Re: Selecting particular key-value pairs in hashes
by merlyn (Sage) on Sep 18, 2004 at 02:58 UTC
      And, of course, you can omit the delete if you want the expression to evaluate to the desired hash without modifying the original data.
      Thanks, merlyn!

      With that, I can now proceed with my coding.

        foreach (keys %hash) { delete($hash{$_}) if ($_ !~ /\d+_\d+/); }
        Going to see if merlyn's example works on my version of Perl... Oh neat, it does. I think his trumps mine by a bit.
Re: Selecting particular key-value pairs in hashes
by bobf (Monsignor) on Sep 18, 2004 at 02:54 UTC

    Simply test the keys against your pattern:

    foreach my $key ( keys %hash ) { if( $key =~ m/\d+_\d+/ ) { print "key = $key, value = $hash{$key}\n"; } }

    Or am I missing something?

    HTH

    Update: I forgot about the "modify hash" requirement - sorry. merlyn came up with a great one-liner, of course!

      Thanks, bobf!

      That was what I was going to do. But if I had proportionately more unwanted key-value pairs, the looping of keys to get to the right key-value pair might become an expensive operation.

      Or some iterative versions which do a little less work:

      # destructive while( my $k = each %hash ) { delete $hash{ $k } unless $k =~ /\d+_\d+/; } # nondestructive my %hash2; while( my( $k, $v ) = each %hash ) { $hash2{ $k } = $v if $k =~ /\d+_\d+/; }
      or maybe
      # destructive /\d+_\d+/ or delete $hash{ $_ } while local $_ = each %hash; # nondestructive my %hash2; /\d+_\d+/ and $hash2{ $_ } = $a while local( $_, $a ) = each %hash;

      Makeshifts last the longest.

Re: Selecting particular key-value pairs in hashes
by steves (Curate) on Sep 18, 2004 at 15:32 UTC
Re: Selecting particular key-value pairs in hashes
by pbeckingham (Parson) on Sep 18, 2004 at 17:05 UTC

    Non-destructively:

    my %hash2 = map {$_ => $hash{$_}} grep {/^\d+_\d+$/} keys %hash;



    pbeckingham - typist, perishable vertebrate.

      You can pick more than one value at a time out of a hash — see merlyn's code and gaal's remark.

      my %hash2 = @hash{ grep /\d+_\d+/, keys %hash };

      Update: thanks to bobf for notifying me that this code makes, uh, very little sense. Here's a hash slice incantation that actually works:

      my %hash2; @hash2{ @$_ } = @hash{ @$_ } for [ grep /\d+_\d+/, keys %hash ]; # or more verbosely my %hash2; { my @key = grep /\d+_\d+/, keys %hash; @hash2{ @key } = @hash{ @key }; }

      Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://391933]
Approved by Aristotle
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2018-01-23 06:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    How did you see in the new year?










    Results (240 votes). Check out past polls.

    Notices?