Combinations, Dispositions and Permutations in PHP
Wh开发者_开发知识库at is the most efficient way to generate all the combinations, dispositions and permutations of an array in PHP?
Here is code to get all permutations:
http://php.net/manual/en/function.shuffle.php#90615
With the code to get the power set, permutations are those of maximal length, the power set should be all combinations. I have no idea what dispositions are, so if you can explain them, that would help.
You can use this class: http://pear.php.net/package/Math_Combinatorics
and use it like:
$combinatorics = new Math_Combinatorics;
$words_arr = array(
'one' => 'a',
'two' => 'b',
'three' => 'c',
'four' => 'd',
);
for ($i=count($words_arr)-1;$i>=1;$i--) {
echo '<br><br>' . $i . ':<br>';
$combinations_arr = $combinatorics->combinations($words_arr, $i);
foreach ($combinations_arr as $combinations_arr_item) {
echo implode(', ', $combinations_arr_item) . '<br>';
}
}
I'd like to suggest my solution of a CombinationsGenerator, which generates combinations of array items.
It's limited to all combinations are of the full length, and not repeats any item. But I believe implementation would not be too hard.
class CombinationsGenerator
{
public function generate(array $list): \Generator
{
if (count($list) > 2) {
for ($i = 0; $i < count($list); $i++) {
$listCopy = $list;
$entry = array_splice($listCopy, $i, 1);
foreach ($this->generate($listCopy) as $combination) {
yield array_merge($entry, $combination);
}
}
} elseif (count($list) > 0) {
yield $list;
if (count($list) > 1) {
yield array_reverse($list);
}
}
}
}
$generator = new \CombinationsGenerator();
foreach ($generator->generate(['A', 'B', 'C', 'D']) as $combination) {
var_dump($combination);
}
It's in PHP7 style, it uses a \Generator
'cause I believe there are good reasons for doing it.
/* Combinations */
function nCr($n, $r)
{
if ($r > $n)
{
return NaN;
}
if (($n - $r) < $r)
{
return nCr($n, ($n - $r));
}
$return = 1;
for ($i = 0; $i < $r; $i++)
{
$return *= ($n - $i) / ($i +1);
}
return $return;
}
/* Permutations */
function nPr($n, $r)
{
if ($r > $n)
{
return NaN;
}
if ($r)
{
return $n * (nPr($n -1, $r -1));
}
else
{
return 1;
}
}
I had to modify @hejdav's answer so that it includes partial combinations, so that it fully delivers all of the results.
I scoured the Internet for this solution and as of June 2019, I believe this is the only publicly accessible answer (anywhere) that truly lists all possible, non-duplicating possibilities.
class CombinationsGenerator
{
/**
* Taken from https://stackoverflow.com/a/39447347/430062.
*
* @param array $list
* @return \Generator
*/
public function generate(array $list): \Generator
{
// Generate even partial combinations.
$list = array_values($list);
$listCount = count($list);
for ($a = 0; $a < $listCount; ++$a) {
yield [$list[$a]];
}
if ($listCount > 2) {
for ($i = 0; $i < count($list); $i++) {
$listCopy = $list;
$entry = array_splice($listCopy, $i, 1);
foreach ($this->generate($listCopy) as $combination) {
yield array_merge($entry, $combination);
}
}
} elseif (count($list) > 0) {
yield $list;
if (count($list) > 1) {
yield array_reverse($list);
}
}
}
}
精彩评论