Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

map-like hash iterator

by jdporter (Canon)
on Nov 06, 2002 at 20:04 UTC ( #210867=snippet: print w/ replies, xml ) Need Help??

Description: In this posting to the Fun With Perl mailing list, I presented a technique for iterating over the elements of a hash, in much the same way that map iterates over the contents of an array.

Yes, you can use map directly, but that means collecting all the keys of the hash up front, and that could be undesirable if the hash is large, or tied.

  sub hasheesh(&\%)
  {
    my( $c, $h ) = @_;
    local( $a, $b );
    @_ = ();
    while ( ( $a, $b ) = each %$h )
    {
      push @_, $c->();
    }
    @_
  }

  # you'd use it like this:
  hasheesh { print "$a => $b\n" } %h;

  # or:
  print hasheesh { "$a => $b\n" } %h;

Comment on map-like hash iterator
Download Code
Re: map-like hash iterator
by jdporter (Canon) on Nov 06, 2002 at 20:15 UTC
    One further note: this uses the package variables $a and $b to communicate the current key and value to the callback. Therefore, this code must be included (e.g. via "require") in each and every namespace where you want to use it.

    As an enhancement, we'd like to avoid the overhead of constructing the result list if the caller won't be using it. --

    sub hasheesh(&\%) { my( $c, $h ) = @_; local( $a, $b ); if ( wantarray ) # list context { @_ = (); while ( ( $a, $b ) = each %$h ) { push @_, $c->(); } return @_; } elsif ( defined wantarray ) # scalar context { my $n; while ( ( $a, $b ) = each %$h ) { my @a = $c->(); $n += @a; } return $n; } else # void context { while ( ( $a, $b ) = each %$h ) { $c->(); } } }

      One further note: this uses the package variables $a and $b to communicate the current key and value to the callback. Therefore, this code must be included (e.g. via "require") in each and every namespace where you want to use it.

      No, not good enough. The package used is the package in which the source code was found.

      Fix:

      sub hasheesh(&\%) { my( $c, $h ) = @_; local( $a, $b ); { no strict 'refs'; *{caller().'::a'} = \$a; *{caller().'::b'} = \$b; } ...rest... }
Re: map-like hash iterator
by Aristotle (Chancellor) on Nov 06, 2002 at 20:19 UTC
    Or maybe even
    sub hashit (&\%) { my ($c, $h) = @_; local ($a, $b); map { ($a, $b) = each %$h; $c->() } (undef) x keys %$h; }

    Makeshifts last the longest.

      Yeah... but if the hash has 10_000_000 keys, it's probably no better to have a list of 10_000_000 undefs than a list of 10_000_000 actual key values.

      Maybe this instead:

      my $n = keys %$h; for ( my $i = 0; $i < $n; $i++ ) { local( $a, $b ) = each %$h; $c->() }

        The idea was to be able to use map to build the return list. Obviously that makes little sense in void context, which is all your for proposition will be able to provide.

        undefs are actually less wasteful than actual values - my @x = (undef) x 10,000,000; consumes 130MB for me, my @x = ('a'x10) x 10,000,000; nearly hits the 500MB mark.

        Of course, if you're not in void context and actually intent on returning the resulting list from processing a 10,000,000 key hash, you'll have to be able to fit that in memory anyway. Since you're throwing around big chunks of data, memory can't be a huge concern, otherwise you'd be walking the hash manually and chewing the bits more carefully.

        You can't have your cake and eat it - you can't be using an iterator when you're concerned about memory usage.

        Makeshifts last the longest.

Re: map-like hash iterator
by particle (Vicar) on Nov 06, 2002 at 23:32 UTC

    see mugwumpjism's prior art in his response to the mapcar -- map for more than one list node.

    code here for those too lazy to click above...

    sub mapeach (&\%) { my $sub = shift; my $hash = shift or do { require Carp; Carp::croak( "mapeach: Nothing to map" ); }; my @ret; while ( my ($k, $v) = each %{$hash}) { local ($_) = $k; push @ret, $sub->($k, $v); } return wantarray ? @ret : { @ret }; }

    ~Particle *accelerates*

      Prior art? He posted that on 2001-11-30. My post to FWP was on 2001-03-29.

        what do you mean, you "get nothing"? Note that you have to have some stuff in your %h hash or you will indeed get no output from the sample code...

Back to Snippets Section

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: snippet [id://210867]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (3)
As of 2014-09-24 03:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (245 votes), past polls