Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??

One way of looping over nested iterators is to combine them into a single iterator that loops over their Cartesian product. In A mini-language for sequences (part 1), I give the code for seq_prod, which does this for sequences, which are similar to iterators.

Assuming that your iterators wrap around upon exhaustion, it is easy to convert them into sequences. Then you can combine them with seq_prod and iterate over the resulting sequence. If you want to work with iterators, you can convert the resulting sequence back into an iterator, or you can write an iter_prod function and avoid sequences altogether. In the example code below, I will take the first route.

Let us say that iterators are defined as follows:

sub iter { my $vals = \@_; my $i = 0; sub { $i >= @$vals ? do { $i = 0; undef } : $vals->[$i++]; }; } sub enumerate_iter { local $Data::Dumper::Indent = 0; local $Data::Dumper::Terse = 1; my ($iter) = @_; my $i = 0; while (defined($_ = $iter->())) { printf "%2d: (%s)\n", $i++, Dumper($_); } print "\n"; } enumerate_iter( iter( qw[a b c] ) ); # 0: ('a') # 1: ('b') # 2: ('c')

Then, the following functions let us convert between iterators and sequences.

sub iter_to_seq { my ($iter) = @_; sub { my $val = $iter->(); defined $val ? ($val) : (); }; } sub seq_to_iter { my ($seq) = @_; sub { my @val = $seq->(); @val ? [@val] : undef; }; } enumerate_iter( seq_to_iter( iter_to_seq( iter( qw[a b c] ) ) ) ); # 0: (['a']) # 1: (['b']) # 2: (['c'])

Note that we wrap sequences with array references in order to convert them into iterators. (Thus the iterator-sequence-iterator round trip is not equivalent to an identity function.)

Finally, with the following functions, we can combine iterators as sequences and convert the resulting sequence back to an iterator. The iter_prod function encapsulates the entire process.

use List::Util qw( reduce ); sub seq_prod { no warnings 'once'; reduce { seq_prod2($a,$b) } @_ ; } sub seq_prod2 { my ($s, $t) = @_; my @sval; sub { my @tval; while ( !@sval || !(@tval = $t->()) ) { return () unless @sval = $s->(); } ( @sval, @tval ); }; } sub iter_prod { seq_to_iter( seq_prod( map iter_to_seq($_), @_ ) ); }

The following example shows how iter_prod works.

my $abcees = iter(qw(a b c)); my $xyzees = iter(qw(x y z)); enumerate_iter( iter_prod( $abcees, $xyzees ) ); # 0: (['a','x']) # 1: (['a','y']) # 2: (['a','z']) # 3: (['b','x']) # 4: (['b','y']) # 5: (['b','z']) # 6: (['c','x']) # 7: (['c','y']) # 8: (['c','z'])

Now you can replace your nested loops with a single loop over the iterator product.

my $product = iter_prod( $abcees, $xyzees ); while (defined (my $vals = $product->())) { my @vars = @$vals; print "Got vars: @vars\n"; # do real work here } # Got vars: a x # Got vars: a y # Got vars: a z # Got vars: b x # Got vars: b y # Got vars: b z # Got vars: c x # Got vars: c y # Got vars: c z

I hope this helps.

Cheers,
Tom


In reply to Re: NestedLoops (Algorithm::Loops) and Iterators by tmoertel
in thread NestedLoops (Algorithm::Loops) and Iterators by mrborisguy

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



  • 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.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (2)
As of 2024-04-19 19:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found