One of my favorite subs:

```sub map_pairs(&@) {
my \$f = shift;
my @res;

no strict 'refs';
no warnings 'once';
my \$caller = caller;
local(*{\$caller."::a"}) = \my \$a;
local(*{\$caller."::b"}) = \my \$b;

push @res, \$f->(\$a,\$b) while (\$a, \$b) = splice @_, 0, 2;
return @res;
}

gives:

```map_pairs { \$a } qw/a b c d/; # ac
map_pairs { \$b } qw/a b c d/; # bd
map_pairs { uc(\$a),lc(\$b) } qw/a b c d/; # AbCd

But, yes, this very much crosses the line out of "one-liner" land

Good Day,
Dean

Replies are listed 'Best First'.
Re^2: Mini-Tutorial: Working with Odd/Even Elements
by ikegami (Pope) on Jul 09, 2009 at 23:26 UTC

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;
}
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 {\$_ = uc(\$a); print "[\$a \$_]\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;    # Not a problem
my %a; local \$a{k};    # Not a problem
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

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().'::'} };

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.

Re^2: Mini-Tutorial: Working with Odd/Even Elements
by LanX (Cardinal) on Jul 10, 2009 at 10:12 UTC
```  local(*{\$caller."::a"}) = \my \$a;
local(*{\$caller."::b"}) = \my \$b;
Does this technique depend on the default "automatic declaration" of \$a and \$b as package-vars? (it's meant for sort {...})

In other words: using \$c for map_triples wouldn't be as easy..(?)

Cheers Rolf

It will be a problem if you are running under strict. However, if the caller sets up \$c as a package variable it will work.

```sub map_triples(&@) {
my \$f = shift;
my @res;

no strict 'refs';
my \$caller = caller;
local(*{\$caller."::a"}) = \my \$a;
local(*{\$caller."::b"}) = \my \$b;
local(*{\$caller."::c"}) = \my \$c;

push @res, \$f->(\$a,\$b,\$c) while (\$a, \$b, \$c) = splice @_, 0, 3;
return @res;
}

use 5.010;
use warnings;
use strict;
our \$c;

say for map_triples { \$a + \$b + \$c } 1..12;

Good Day,
Dean

hmm .. maybe an approach using the @_-Array (i.e. \$_ instead \$a and so on) is more scalable...

Cheers Rolf

Re^2: Mini-Tutorial: Working with Odd/Even Elements
by Roy Johnson (Monsignor) on Jul 10, 2009 at 18:45 UTC
Update: figured it out (simulthanks to Ikegami). Gotta reference the right package. Corrected solution:
```sub map_pairs(&@) {
my \$fn = shift;

my \$pkg = caller;

map {
my \$idx = \$_ * 2;
no strict 'refs';
my (\$a, \$b)
= local (\${\$pkg.'::a'}, \${\$pkg.'::b'})
= (@_[\$idx,\$idx+1]);
\$fn->(\$a, \$b);
} (0..\$#_/2);
}
Previous, erroneous solution follows.

I think you made this harder than it needs to be. Isn't this equivalent?

```sub map_pairs(&@) {
my \$fn = shift;
map {
my \$idx = \$_ * 2;
local (\$a, \$b) = @_[\$idx,\$idx+1];
\$fn->(\$a, \$b);
} (0..\$#_/2);
}