http://www.perlmonks.org?node_id=1193849


in reply to Re: Minimally changing combinations
in thread Minimally changing combinations

It was easy once I figured out that it's just like counting... hope to have time this weekend to make it more feature-ful and put it on CPAN!
#!/usr/bin/env perl use strict; use warnings; use Data::Dump; sub single_change_iterator { my @domains = @_; my $it = 0; my @dir = (1) x @domains; my @pos = (0) x @domains; $it = sub { # Initializion. Next call, use the real iterator. $it = sub { my $cur_dom; for ($cur_dom = 0; $cur_dom < @domains or return; # No more changes! ++$cur_dom) { # Are we at end position of this domain? my $upward = $dir[$cur_dom]==1; if ($pos[$cur_dom] == ($upward ? $#{$domains[$cur_dom] +} : 0)) { # flip domain's direction, let loop continue $dir[$cur_dom] *= -1; } else { # Move current domain to next position $pos[$cur_dom] += $dir[$cur_dom]; last; } } return [$cur_dom, $domains[$cur_dom][$pos[$cur_dom]]]; }; # End first call by initializing all domains return map [$_, $domains[$_][0]], 0 .. $#domains }; return \$it; } my $combo_it = single_change_iterator(['X','Y'], [qw(a b c)], [44,55]) +; my @changes; dd @changes while @changes = &$$combo_it; =head1 NAME single_change_itertor - Help build Cartesian product, by changing one +value at a time =head1 SYNOPSIS use Data::Dump; my $it = single_change_itertor(['X','Y'], [qw(a b c)], [1,2]); dd $_ while $_ = &$$it; prints ([0, "X"], [1, "a"], [2, 44]) [0, "Y"] [1, "b"] [0, "X"] [1, "c"] [0, "Y"] [2, 55] [0, "X"] [1, "b"] [0, "Y"] [1, "a"] [0, "X"] =head1 DESCRIPTION This finds a way to cycle through all possible combinations of the given sets- their Cartesian Product- by changing a single element at a time. Given a set of domains, returns a handle to an iterator showing which position changes, and what to. Similar to a Gray code, which cycles through a set of numbers while only changing one digit. Each call returns a list of array references. The inner array reference is a pair, [ index of domain that has a change , new value ] The first iteration returns a pair for each domain so as to initialize all the domains. Each subsequent call returns a single pair.