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

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.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^4: map and grep (but for hashes)
by shmem (Chancellor) on Jan 30, 2009 at 22:23 UTC

    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?

    ;-)
      local @_ = ($_[$i],$_[$i+1]); $code->(@_) and push @rv, @_;

      is the same as

      my @args = ($_[$i],$_[$i+1]); $code->(@args) and push @rv, @args;

      Did you mean the following (which allows elements to be added and removed from @_) or did you repurpose a package variable for nothing?

      local @_ = ($_[$i],$_[$i+1]); &$code and push @rv, @_;

        I confess, I did repurpose a package variable for nothing. I'm going to abstain from PerlMonks for some hours to do penitence, and bonk my head... ;-)

Re^4: map and grep (but for hashes)
by zerohero (Monk) on Jan 30, 2009 at 21:14 UTC

    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.

      develop a new school of Perl Fu around this new potent weapon!

      I assumed that you already has uses for them, and I'm not at all convinced about their potency. By flattening the hash to a list, you've effectively thrown away most all the properties that make hashes so useful:

      1. O(1) lookup.
      2. exists

      The most effective uses of hashes involve going directly to the items of interest and avoiding having to iterate the entire structure.

      It's an interesting exercise to construct them, but I think that the uses will be fairly limited. If there were a raft of good uses, someone would have invented them before now.


      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.

        I only realized later that the version flattened to list, which I think was an ambiguity in my spec, i.e. "to make this work like map and grep", only for hashes. The spec was imperfect, but a valuable place to start, naively, to zero in on the real question (it's often hard to ask a precise question at the beginning of a task).

        In fact, this school of programming already exists, and it's called "functional programming". That it's powerful is already demonstrated in many real world applications. map is borrowed from functional programming, and is the simplest, first order example of it. So at the heart of my question was is there any other functional programming support in Perl, besides map? For example transformations that take hashes to hashes, and can be composed? Let's try hmap.

        It's not that I couldn't write the code for this myself (once I figured out what the spec actually was). However, there was the sneaking feeling that this was already done, well understood, and there would be better techniques for it.

        Thanks for taking the time to answer my questions. I learn a lot with each round of discourse.