- Edited
Permutations!
A couple of generators: pass one an array and it have it successively crank out different permutations of the array's elements. ("Different", that is, if all of the input array's elements are distinct.)
One yields the permutations in lexicographic ("dictionary") order. Think of the array as a word written in some weird alphabet (its elements being the letters), and taking the order of letters in that word to be "alphabetical" (an English example of such a word would be "begins") and then listing all the rearrangements of those letters in alphabetical order ("begisn", "begnis", "begnsi", ... "singbe", ... "snigeb").
a b c
a c b
b a c
b c a
c a b
c b a
The other is what bell-ringers call "plain change" order: it's a minimum-change (meaning only two elements change positions each time) permutation that always swaps two adjacent elements. It's implemented recursively here, by weaving the nth element back and forth through the elements of the previous permutations.
a b c
b a c
b c a
c b a
c a b
a c b
So, here's the code.
function lexicographic_permutations($l)
{
$n = count($l);
if($n == 0 || $n == 1)
{
yield $l;
}
elseif($n == 2)
{
yield $l;
yield array_reverse($l);
}
else
{
for($i = 0; $i < $n; ++$i)
{
$new = $l;
$li = $new[$i];
unset($new[$i]);
foreach(lexicographic_permutations(array_values($new)) as $v)
{
array_unshift($v, $li);
yield $v;
}
}
}
}
function plain_changes_permutations($l)
{
$n = count($l);
if($n == 0)
{
yield $l;
}
else
{
$first = [array_shift($l)];
--$n;
$ascending = 1;
foreach(plain_changes_permutations($l) as $subperm)
{
$to = $n * $ascending;
$from = $n - $to;
foreach(range($from, $to) as $i)
{
$perm = $subperm;
array_splice($perm, $i, 0, $first);
yield $perm;
}
$ascending = 1 - $ascending;
}
}
}