Skip to content

Instantly share code, notes, and snippets.

@littlefuntik
Last active October 30, 2017 16:50
Show Gist options
  • Save littlefuntik/5b6970fdbaba0755a4c3417d514e06c1 to your computer and use it in GitHub Desktop.
Save littlefuntik/5b6970fdbaba0755a4c3417d514e06c1 to your computer and use it in GitHub Desktop.
Python function permutations in PHP language.
<?php
require 'permutations.php';
$timeStart = microtime(true);
$memoryStart = memory_get_usage();
$i = 0;
foreach (permutations(range(1, 3), 2) as $combo) {
echo json_encode($combo) . PHP_EOL;
++$i;
}
$_timeSeconds = microtime(true) - $timeStart;
$_memoryUsageMb = (memory_get_usage() - $memoryStart) / 1024 / 1024;
echo 'Total count: ' . $i . PHP_EOL;
echo 'Time seconds, s: ' . $_timeSeconds . PHP_EOL;
echo 'Memory usage, M: ' . $_memoryUsageMb . PHP_EOL;
die;
<?php
function py_range($start, $stop = null, $step = null)
{
if (null === $stop) {
$stop = $start;
$start = 0;
}
if (null === $step) {
if ($start > $stop) {
return [];
}
--$stop;
return range($start, $stop);
} elseif (-1 === $step) {
if ($start > $stop) {
list($start, $stop) = [$stop, $start];
}
++$start;
return array_reverse(range($start, $stop));
} else {
if ($start > $stop) {
return [];
}
return range($start, $stop, $step);
}
}
/**
* Return successive r length permutations of elements in the iterable.
*
* If r is not specified or is None, then r defaults to the length of the iterable and all possible full-length permutations are generated.
*
* Permutations are emitted in lexicographic sort order. So, if the input iterable is sorted, the permutation tuples will be produced in sorted order.
*
* Elements are treated as unique based on their position, not on their value. So if the input elements are unique, there will be no repeat values in each permutation.
*
* Example usage,
*
* ```php
* $i = 0;
* foreach (permutations(range(1, 3), 2) as $combo) {
* echo json_encode($combo) . "\n";
* ++$i;
* }
* echo 'Total count: ' . $i . "\n";
* ```
*
* Outputs,
*
* ```
* [1,2]
* [1,3]
* [2,1]
* [2,3]
* [3,1]
* [3,2]
* Total count: 6
* ```
*
* @link https://docs.python.org/3/library/itertools.html#itertools.permutations itertools.permutations (source)
*
* @param array $pool
* @param null|int $r
*
* @return \Generator
*/
function permutations($pool, $r = null)
{
$n = count($pool);
$r = (null === $r) ? $n : $r;
if ($r <= $n) {
$indices = py_range($n);
$cycles = py_range($n, $n - $r, -1);
$ret = [];
foreach (array_slice($indices, 0, $r) as $i) {
$ret[] = $pool[$i];
unset($i);
}
yield $ret;
while ($n) {
$isDone = true;
foreach (array_reverse(py_range($r)) as $i) {
$cycles[$i] -= 1;
if (0 === $cycles[$i]) {
$indices = array_merge(
array_slice($indices, 0, $i),
array_merge(
array_slice($indices, $i + 1),
array_slice($indices, $i, 1)
)
);
$cycles[$i] = $n - $i;
} else {
$j = $cycles[$i];
// swap array values: $i and $tmpKey
$tmpValue = $indices[$i];
$tmpKey = count($indices) - $j;
$indices[$i] = $indices[$tmpKey];
$indices[$tmpKey] = $tmpValue;
unset($tmp, $y);
$ret = [];
foreach (array_slice($indices, 0, $r) as $i0) {
$ret[] = $pool[$i0];
}
yield $ret;
$isDone = false;
break;
}
}
if ($isDone) {
break;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment