Here are some attempts at improving performance, compared to the solutions already posted (of which BrowserUK's recursive solution was the fastest):
Branching solution
A trivial (but non-elegant) way to gain performance is to directly implement the nested loops for a few (presumably common) values of n, using if/elsif/else to branch between them, and only fall back to the general-case recursive implementation for higher values of n:
sub multi_foreach(&@) {
my $code = shift;
if (@_ == 1) {
for my $i (@{ shift() }) {
$code->( $i );
}
}
elsif (@_ == 2) {
my ($a0, $a1) = @_;
for my $i0 (@$a0) {
for my $i1 (@$a1) {
$code->( $i0, $i1 );
}
}
}
elsif (@_ > 2) {
my ($a0, $a1, $a2, @rest) = @_;
for my $i0 (@$a0) {
for my $i1 (@$a1) {
for my $i2 (@$a2) {
if (@rest) {
&multi_foreach_recursive( $code, scalar @rest,
@rest, $i0, $i1, $i2 );
}
else { $code->( $i0, $i1, $i2 ); }
}
}
}
}
}
multi_foreach { say join ' ', @_ } \( @a, @b, @c );
eval solution
The logical generalization of the branching solution, would be to dynamically generate the nested foreach loops for arbitrary levels of nesting. This incurs an overhead for code-generation each time the algorithm is called (PS: caching could help), but once generated the actual looping code will run very fast. Thus this solution tends to be slower than the recursive solution for small inputs, but faster for large inputs (i.e. many big arrays):
sub multi_foreach(&@) {
my $code = shift;
my ($head, $inside, $tail) = ('', '$code->(', ')');
foreach (0..$#_) {
$head .= "for my \$i$_ (\@{\$_[$_]}) { ";
$inside .= "\$i$_, ";
$tail .= ' }';
}
eval( $head . $inside . $tail );
}
multi_foreach { say join ' ', @_ } \( @a, @b, @c );
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.