Hi

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


In reply to Efficient but elegant Cross-Product iterator ? by LanX

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.