Here's how it emerged:
Just as an exercise, I wanted to generate a list of strings with a specific length from every possible combination of a list of characters.
But not with for loops, but with nested maps! In its simplest form, with 2 chars and strings with a length of two:
my @a = qw( a b ); my @b = map { my $x = $_; map { $x . $_ } @a; } @a;
This produces aa, ab, ba, bb.
Adding characters is easy:
my @a = qw( a b c );
This produces aa, ab, ac, ba, bb, bc, ca, cb, cc.
But increasing the length of the string is not so easy. I did this by adding another nested map:
my @b = map { my $x = $_; map { my $y = $_; map { $x . $y . $_ } @a; } @a; } @a;
which, with qw( a b ), produces aaa, aab, aba, abb, baa, bab, bba, bbb. This is, of course, stupid.
One way to solve this problem is with a recursive function:
sub f { my ( $n, @a ) = @_; croak "illegal value for n: $n" if $n < 1; return @a if $n == 1; map { my $x = $_; map { $x . $_ ) } f( $n - 1, @a ); } @a; }
Now you could make it more general by adding a coderef parameter, string concatenation being only a special case needed in the original example:
sub f { my ( $n, $g, @a ) = @_; croak "illegal value for n: $n" if $n < 1; return @a if $n == 1; map { my $x = $_; map { $g->( $x, $_ ) } f( $n - 1, $g, @a ); } @a; }
So we have a function f that produces a list b by applying a function g to all possible combinations of a list a by calling itself recursively n times.
Is this useful? Or could it be further transformed so that it yields something useful?
In reply to nested maps by jczeus
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |