Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Re: Variable number of foreach loops (improving performance)

by smls (Friar)
on Dec 11, 2013 at 11:35 UTC ( #1066607=note: print w/replies, xml ) Need Help??


in reply to Variable number of foreach loops

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 );

Replies are listed 'Best First'.
Re^2: Variable number of foreach loops (improving performance)
by tobyink (Canon) on Dec 11, 2013 at 11:47 UTC

    You'll gain a lot more speed rewriting it in XS and using the multicall interface to call $code.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (6)
As of 2022-01-24 14:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:












    Results (64 votes). Check out past polls.

    Notices?