TL;DR

Letâ€™s turn our iterative solution from A simplified iterative implementation of NestedLoops into an iterator.

Itâ€™s about time to turn the iterative solution for NestedLoops into an iterator. We will start from the optimized version found in Benchmarking simplified implementations of NestedLoops:

`````` 1 sub nested_loops_iterative {
2    my (\$dims, \$opts, \$cb) = @_;
3    return unless scalar @{\$dims};
4    (\$opts, \$cb) = (\$cb, \$opts) if ref(\$opts) eq 'CODE';
5    my @indexes     = (-1);
6    my @accumulator = (undef) x scalar @{\$dims};
7    while ((my \$level = \$#indexes) >= 0) {
8       my \$dimension = \$dims->[\$level];
9       my \$i         = ++\$indexes[\$level];    # advance in "this" slot
10       if (\$i > \$#{\$dimension}) { pop @indexes }
11       else {
12          \$accumulator[\$level] = \$dimension->[\$i];
13          if   (\$level == \$#{\$dims}) { \$cb->(@accumulator) }
14          else                       { push @indexes, -1 }
15       }
16    } ## end while ((my \$level = \$#indexes...))
17    return;
18 } ## end sub nested_loops_iterative
``````

Itâ€™s quite clear that `@indexes` and `@accumulator` will keep track of the state, and that instead of calling the `\$cb` as in line 13 we will have â€śjustâ€ť to return the contents of `@accumulator`:

`````` 1 sub nested_loops_iterator {
2    my (\$dims, \$opts, \$cb, \$accumulator) = @_;
3    return unless scalar @{\$dims};
4    (\$opts, \$cb) = (\$cb, \$opts) if ref(\$opts) eq 'CODE';
5    my @indexes     = (-1);
6    my @accumulator = (undef) x scalar @{\$dims};
7    return sub {
8       while ((my \$level = \$#indexes) >= 0) {
9          my \$dimension = \$dims->[\$level];
10          my \$i         = ++\$indexes[\$level];
11          if (\$i > \$#{\$dimension}) { pop @indexes }
12          else {
13             \$accumulator[\$level] = \$dimension->[\$i];
14             if   (\$level == \$#{\$dims}) { return @accumulator }
15             else                       { push @indexes, -1 }
16          }
17       }
18       return;
19    }
20 }
``````

As you can see, the change is quite minimal!

A full modulino is shown below:

Until next timeâ€¦ take care!

Comments? Octodon, , GitHub, Reddit, or drop me a line!