LanX has asked for the wisdom of the Perl Monks concerning the following question:
I'm trying to create an iterator which takes a list of subs and creates the cross product of the returned lists:
the expected result is
for my $x ( $sub_x->() ) { for my $y ( $sub_y->() ) { return [ $x,$y ]; } }
Please note that an iterator can be interrupted and resumed, and that the numbers of subs (=nesting levels) should be free.
Since function calls are expensive in Perl I tried to implement it as a big while loop instead of recursive calls.
Now I'm wondering if there is a more elegant or faster way to code this:
use 5.12.0; use strict; use warnings; use Data::Dump qw/pp dd/; my $DBG; ;;; # skipped $DBG = 0; my $i_cross = cross( sub {"A".."B"}, sub {1..2}, sub {"a".."b"}, ); my $count = 4; while ( my ($v) = $i_cross->() ) { warn "*** First 5 RESULTs: ", pp $v; last unless $count--; } warn "stopped"; while ( my ($v) = $i_cross->() ) { warn "*** Remaining RESULT: ", pp $v; } sub cross { my @stack = @_; my $level = 0; my @ranges = (); my @res; return sub { while ( $level >= 0 ) { my $ra_range = \ $ranges[$level]; # ENTER LOOP unless (defined $$ra_range ) { $$ra_range = [ $stack[$level]->() ]; warn "ENTER level=$level left \@ranges=" ,pp \@ranges + if $DBG; } # LOOP OVER if ( @$$ra_range ) { $res[$level] = shift @$$ra_range ; # deepest level? if ( $level == $#stack ) { return [@res]; } # go deeper else { $level++; } } #EXIT LOOP: else { $level--; $$ra_range = undef; } } return; } }
RESULT
*** First 5 RESULTs: ["A", 1, "a"] at d:/exp/iter/cross.pl line 92. *** First 5 RESULTs: ["A", 1, "b"] at d:/exp/iter/cross.pl line 92. *** First 5 RESULTs: ["A", 2, "a"] at d:/exp/iter/cross.pl line 92. *** First 5 RESULTs: ["A", 2, "b"] at d:/exp/iter/cross.pl line 92. *** First 5 RESULTs: ["B", 1, "a"] at d:/exp/iter/cross.pl line 92. stopped at d:/exp/iter/cross.pl line 96. *** Remaining RESULT: ["B", 1, "b"] at d:/exp/iter/cross.pl line 99. *** Remaining RESULT: ["B", 2, "a"] at d:/exp/iter/cross.pl line 99. *** Remaining RESULT: ["B", 2, "b"] at d:/exp/iter/cross.pl line 99.
(it's part of a bigger file, so don't worry about the line numbers)
Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery
|
|---|