Published on 22 Apr 2011. Tagged with php.
This function calculates the n-th permutation of the elements in an array using an iterative approach. It does not rely on recursion.
<?php // This code is public domain. The original author is Marc Ermshaus.
error_reporting(-1);
/**
* Calculates the factorial of a given non-negative integer
*
* @param int $n Non-negative integer
* @return int Factorial of $n
*/
function fac($n)
{
if (!is_int($n) || $n < 0) {
throw new InvalidArgumentException(
'n has to be a non-negative (int)');
}
for ($f = 1; $n > 1; $n--) {
$f *= $n;
}
return $f;
};
/**
* Returns a specific permutation of an array
*
* This function does not preserve key/value pairs.
*
* Permutation table for input (a, b, c):
*
* n result
* -------------
* ...
* -6 a, b, c initial state
* -5 a, c, b
* -4 b, a, c
* -3 b, c, a
* -2 c, a, b
* -1 c, b, a
* 0 a, b, c initial state
* 1 a, c, b
* 2 b, a, c
* 3 b, c, a
* 4 c, a, b
* 5 c, b, a
* 6 a, b, c initial state
* ...
*
* @param array $items Array to calculate permutation of
* @param int $n Index of wanted permutation
* @return array Resulting array
*/
function getNthPermutation(array $items, $n)
{
if (!is_int($n)) {
throw new InvalidArgumentException(
'n has to be an (int)');
}
$n = (int) $n;
$result = array();
$l = count($items);
$facL = fac($l);
while ($n < 0) {
$n += $facL;
}
$n = $n % $facL;
for ($i = 1; $l >= $i; $i++) {
$facLI = fac($l - $i);
// Calculate current index in $items
$k = (int) ($n / $facLI);
// Remove element from items and push to result
$curItem = array_splice($items, $k, 1);
$result[] = $curItem[0];
$n -= $k * $facLI;
}
return $result;
}
header('content-type: text/plain');
$items = range('a', 'd');
$f = fac(count($items));
for ($i = $f * -2; $i <= $f * 2; $i++) {
printf("% 3d : %s\n", $i, join(', ', getNthPermutation($items, $i)));
}