in reply to Re^6: map and grep (but for hashes)
in thread map and grep (but for hashes)

If you're looking for composability and flexibility, this version will

  1. accept either a list of hashref;
  2. return a list or hashref in context;
  3. provides key and value as: $a & $b; and in @_; and the value as $_.

Which allows your composed "query" to operate fairly naturally:

my %new = hmap { exists $b->{ nick } && $b->{ nick } =~ m[^(?:rbush|fred)$] ? ( $a => scalar hgrep{ $a =~ m[^(nick|phone)$] } $b ) : () } \%old;

Code and tests

#! perl -slw use strict; use Carp; use Data::Dump qw[ pp ]; sub hmap (&@) { our( $a, $b ); my $code = shift; croak "Even sized list or hash ref required" if @_ & 1 and not @_ == 1 && ref( $_[0] ) =~ m[HASH]; @_ = %{ $_[0] } if @_ == 1; my @rv; while( @_ ) { local( $a, $b ) = splice( @_, 0, 2 ), my $rv = $code->( $a, local $_ = $b ); push @rv, $rv ? ( $a, $rv ) : (); } wantarray ? @rv : { @rv }; } sub hgrep (&%) { our( $a, $b ); my $code = shift; croak "Even sized list or hash ref required" if @_ & 1 and not @_ == 1 && ref( $_[0] ) =~ m[HASH]; @_ = %{ $_[0] } if @_ == 1; my @rv; while( @_ ) { local( $a, $b ) = splice( @_, 0, 2 ); my $rv = $code->( $a, local $_ = $b); push @rv, $rv ? ( $a, $b ) : (); } wantarray ? @rv : { @rv }; } my %h = ( 'a' .. 'j', 's' .. 'z' ); pp 'start: ', \%h; my %r1 = hmap{ ++$b } %h; pp 'incr values: ', \%r1; my $r2 = hmap{ ++$_ } %r1; pp 'and again: ', $r2; my %h3 = hmap{ ++$_[1] } $r2; pp 'and once more: ', \%h3; my %s = hgrep{ $a le 'm' } %h; pp 'filter keys le m: ', \%s; my $t = hgrep{ length $b > 1 } \%h3; pp 'filter values longer than 1 char: ', $t; print "\n-----------\n"; my %old = ( '1' => { 'nick' => 'rbush', 'bday' => '3/12/1965', 'phone' => '555 +1212' }, '5' => { 'nick' => 'fred', 'bday' => '5/01/1972', 'phone' => '111 +2300' }, '11'=> { 'nick' => 'joan', 'bday' => '1/02/2033', 'phone' => '123 +456789' }, ); my %new = hmap { exists $b->{ nick } && $b->{ nick } =~ m[^(?:rbush|fred)$] ? ( $a => scalar hgrep{ $a =~ m[^(nick|phone)$] } $b ) : () } \%old; pp \%new; __END__ c:\test>hmap ( "start: ", { a => "b", c => "d", e => "f", g => "h", i => "j", "s" => "t", u => + "v", w => "x", "y" => "z" }, ) ( "incr values: ", { a => "c", c => "e", e => "g", g => "i", i => "k", "s" => "u", u => + "w", w => "y", "y" => "aa" }, ) ( "and again: ", { a => "d", c => "f", e => "h", g => "j", i => "l", "s" => "v", u => + "x", w => "z", "y" => "ab" }, ) ( "and once more: ", { a => "e", c => "g", e => "i", g => "k", i => "m", "s" => "w", u => + "y", w => "aa", "y" => "ac" }, ) ( "filter keys le m: ", { a => "b", c => "d", e => "f", g => "h", i => "j" }, ) ( "filter values longer than 1 char: ", { w => "aa", "y" => "ac" }, ) ----------- { 1 => { nick => "rbush", phone => 5551212 }, 5 => { nick => "fred", phone => 1112300 }, }

That done, the next thing you are likely to want, is to be able to process arrays nested in hashes; and hashes nested in arrays; and conditionally either. At which point you are moving into the realms of the provisions of Data::Rmap.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^8: map and grep (but for hashes)
by zerohero (Monk) on Feb 02, 2009 at 17:57 UTC
    Thanks for the pointers. I'm also about halfway through "Higher Order Perl" which seems to give a few nuggets as well (although the first chapters are a pretty long rehash of recursion). It's become clear that part of my struggle is figuring out the Perl syntax around lists and subroutines (e.g. used in closures). I'm good with hierarchical anonymous structures, but clearly some of my lack of precise syntactical knowledge is holding me back. Anyway, thanks for all the pointers!