in reply to map and grep (but for hashes)

Not pre-existing, but something along these lines?

#! perl -slw use strict; sub hmap(&%) { use vars qw[ $h $v ]; my $code = shift; my @rv; local( $h, $v ) = splice( @_, 0, 2 ), push @rv, $code->() while @_; return @rv } sub hgrep (&%) { use vars qw[ $h $v ]; my $code = shift; my @rv; local( $h, $v ) = splice( @_, 0, 2 ), push @rv, $code->() ? ( $h, $v ) : () while @_; return @rv; } my %h = 'a' .. 'z'; print %h; my %r = hmap{ $h => ++$v } %h; print %r; my %s = hgrep{ $h le 'm' } %r; print %s; __END__ [19:25:50.05] C:\test>hmap wxefabmnstyzuvcdklqrghijop egwyacmosuyaauwcekmgiqsoqik egcekmacgimoik

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^2: map and grep (but for hashes)
by shmem (Chancellor) on Jan 30, 2009 at 20:51 UTC

    Wonderful! But slightly off the specs. Well, perhaps. ;-)

    #!perl -l # sub hmap (&%) { my $code = shift; local $_; my @rv; push @rv, shift, $code->($_=shift) while @_; @rv; } sub hgrep (&%) { my $code = shift; local $_; my @rv; push (@rv, ($code->($_=$_[1]) ? (shift,$_):())),shift while @_; @rv; } %h = (foo => 1, bar => 2, baz => 3); %new = hmap { ++$_ } %h; print "hmap result:"; print "$_ => $new{$_}" for keys %new; %new = hgrep { /2/ } %h; print "hgrep result:"; print "found $_ => $new{$_}" for keys %new; __END__ hmap result: bar => 3 baz => 4 foo => 2 hgrep result: bar => 2

    update: well, this operates on the value only, localizing $_ and doesn't create package vars. For the key... hm. What do we have? $", $/, $\ ... - no, they could be used inside the block. But then... we could localize @_ here!

    sub hmap (&%) { my $code = shift; my @i = @_; local @_; my @rv; push @rv, $code->(@_=(shift @i,shift @i)) while @i; @rv; } %h = (foo => 1, bar => 2, baz => 3); %new = hmap { $_[0]."l",++$_[1] } %h; print "hmap result:"; print "$_ => $new{$_}" for keys %new; __END__ hmap result: bazl => 4 barl => 3 fool => 2

    update 2: BrowserUk, as you may have noticed, I ommitted the 'hgrep' part here, since my solution doesn't work - seem to not dunno how to change its arguments inside the block... ;-)

      But slightly off the specs.

      You're missing the " k = something," part of the spec :) How about?

      #! perl -slw use strict; sub hmap(&%) { use vars qw[ $h ]; my $code = shift; my @rv; local( $h, $_ ) = splice( @_, 0, 2 ), push @rv, $h, $code->() while @_; return @rv } sub hgrep (&%) { use vars qw[ $h ]; my $code = shift; my @rv; local( $h, $_ ) = splice( @_, 0, 2 ), push @rv, $code->() ? ( $h, $_ ) : () while @_; return @rv; } my %h = 'a' .. 'z'; print %h; my %r = hmap{ ++$_ } %h; print %r; my %s = hgrep{ $h le 'm' } %r; print %s; __END__ [19:25:50.05] C:\test>hmap wxefabmnstyzuvcdklqrghijop egwyacmosuyaauwcekmgiqsoqik egcekmacgimoik

      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.

        Okay... now here's the next quick shot after some trying. Have to look at the failed attempts. This really a fun challenge, zerohero++ ;-)

        Since $_ is localized for map and grep, it seems the most natural thing to localize @_ for that purpose, and it seems to work... (update: heh, but it hasn't to be localized - perl does that for us)

        #!perl -l # sub hmap (&%) { my $code = shift; @_ % 2 and die "odd number of variables for hmap"; my @i = @_; my @rv; push @rv, $code->(@_=(shift @i,shift @i)) while @i; @rv; } sub hgrep (&%) { my $code = shift; @_ % 2 and die "odd number of variables for hgrep"; my @i = @_; my @rv; for(my $i = 0; $i<= $#_; $i+=2) { local @_ = ($_[$i],$_[$i+1]); $code->(@_) and push @rv, @_; } @rv; } %h = (foo => 1, bar => 2, baz => 3); %new = hmap { $_[0]."l",++$_[1] } %h; print "hmap result:"; print "$_ => $new{$_}" for keys %new; print "original \%h:"; print "$_ => $h{$_}" for keys %h; %new = hgrep { $_[0] =~ /f/ and ($_[0].="l") and $_[1] =~ /1/ and $_[1] += 41; } %h; print "hgrep result:"; print "$_ => $new{$_}" for keys %new; print "original \%h:"; print "$_ => $h{$_}" for keys %h; __END__ hmap result: bazl => 4 barl => 3 fool => 2 original %h: bar => 2 baz => 3 foo => 1 hgrep result: fool => 42 original %h: bar => 2 baz => 3 foo => 1

        No package vars introduced. But it looks like in hgrep localizing @_ is necessary, however in hmap it isn't. Why?

        ;-)

        For the final challenge, develop a new school of Perl Fu around this new potent weapon! If so much is possible with map and grep, think of the new possibilities.

      True, ok, so one refinement would be you'd likely need some way to look at the key, and not just the value. It seems like the way to do this is by using a local variable as in the previous example.

Re^2: map and grep (but for hashes)
by zerohero (Monk) on Jan 30, 2009 at 20:58 UTC

    Very nice. As Wayne and Garth would say "We're not worthy!" This is much better than what I would have come up with, and I'm going to have to study some of the little details here.

    The cool thing is this seems to look and smell like map and grep but for hashes.

    God I love perl.

    THANKS!