in reply to Re: Mini-Tutorial: Working with Odd/Even Elements
in thread Mini-Tutorial: Working with Odd/Even Elements

I was surprised by the lack of such a function in List::MoreUtils recently. There is natatime, but it returns an iterator rather than using a callback.

I wonder how much speed you'd gain by replacing $f->($a,$b) with &$f. Another advanced feature for the collection!

It would be a nice bonus if you $a and $b were aliases to the args like with map.

sub map_pairs(&@) { my $cb = shift; my $caller = caller(); my $ap = do { no strict 'refs'; \*{$caller.'::a'} }; my $bp = do { no strict 'refs'; \*{$caller.'::b'} }; local *$ap; local *$bp; my @res; while (@_) { *$ap = \shift; *$bp = \shift; push @res, &$cb; } return @res; }

Replies are listed 'Best First'.
Re^3: Mini-Tutorial: Working with Odd/Even Elements
by Roy Johnson (Monsignor) on Jul 10, 2009 at 19:52 UTC
    Too golfy or arcane? (fixed now)
    sub map_pairs(&@) { my $fn = shift; my $pkg = $main::{caller().'::'}; map { @{$pkg}{qw(a b)} = \(@_[0,1]); $fn->(shift, shift); } (0..$#_/2); } package Smarter; our($a, $b) = qw(orig value); my @arr = qw(a b c d); print main::map_pairs {$_[0] = uc($a); print "[$a $_[1]]\n"; $a} @arr; print "\n"; print "Now @arr\n"; print "\n$a $b\n";
    I like being able to avoid sym refs and all the globbage. The interesting thing to note is that I seem to get a magical localization of my variables.

    Caution: Contents may have been coded under pressure.

      Too golfy or arcane?

      All of these map_pairs implementations are in the red zone of the arcanometer.

      The interesting thing to note is that I seem to get a magical localization of my variables.

      Array elements aren't lexical variables, if that's what you're talking about.

      As for using local on array elements, perlsub says

      Some types of lvalues can be localized as well : hash and array elements and slices, conditionals (provided that their result is always localizable), and symbolic references. As for simple variables, this creates new, dynamically scoped values.

      That means

      my @a; local $a[0]; # Not a problem my %a; local $a{k}; # Not a problem
        Array elements aren't lexical variables, if that's what you're talking about.
        No, I was saying that my "orig value" came back without my making them local (see the other reply to my node), but apparently that's not a reliable feature. I was using ActivePerl, for the record.

        Caution: Contents may have been coded under pressure.
      The interesting thing to note is that I seem to get a magical localization of my variables.
      that's the output I get
      [A b] [C d] AC Now A b C d C d
      "orig" and "value" are lost, so no "magical localization". but adding local
          local @{$pkg}{qw(a b)} = \(@_[0,1]);
      produces
      [A b] [C d] AC Now A b C d orig value

      Cheers Rolf

      UPDATE:This was perl, v5.10.0 built for i486-linux-gnu-thread-multi
        That's what I would have expected. Thanks for the data point. I was wondering whether there was some obscure documented reason it should behave as I was seeing.

        Caution: Contents may have been coded under pressure.

      By the way, your fixed is still broken. It only works if the calling package is one level away from the root. If the caller is Foo, it works. If the caller is Foo::Bar, it doesn't.

      Using a symbolic ref is simpler than using %::.

      my $pkg = do { no strict 'refs'; *{caller().'::'} };
Re^3: Mini-Tutorial: Working with Odd/Even Elements
by duelafn (Vicar) on Jul 10, 2009 at 11:15 UTC

    Actually, I like passing the arguments so that I can do things like this: (sum doesn't know to look at $a and $b)

    use List::Util qw/sum/; say for map_pairs \&sum, 1..10;

    I do like the aliasing bonus, but it seems to not work on hash keys:

    use YAML; my @array = ( foo_name => " Bob Smiley ", foo_age => " 32" ); map_pairs { $a =~ s/foo_//; s/^\s+//, s/\s+$// for $b; } @array; print Dump \@array; my %hash = ( foo_name => " Bob Smiley ", foo_age => " 32" ); map_pairs { $a =~ s/foo_//; s/^\s+//, s/\s+$// for $b; } %hash; print Dump \%hash;

    outputs

    --- - name - Bob Smiley - age - 32 --- foo_age: 32 foo_name: Bob Smiley

    Good Day,
        Dean

      It's not a problem with map_pairs. You'll notice the same with map and for.

      Hash keys aren't Perl variables (aren't an SV), so %hash can't possibly return an alias to them. It returns a copy.

      It could return something magical that would result in the keys being "changed", but it doesn't. One could make a tie implementation if one needed such a feature.