Permutations - all possible sets of numbers

2019-01-01 01:10发布

I have numbers, from 0 to 8. I would like in result, all possible sets of those numbers, each set should use all numbers, each number can occur only once in a set.

I would like to see solution made in PHP that could print out result. Or, at least, I would like some refreshment in theory of combinatorics, as I have long forgotten it. What is the formula to calculate how many permutations will there be?

Example sets:

  • 0-1-2-3-4-5-6-7-8
  • 0-1-2-3-4-5-6-8-7
  • 0-1-2-3-4-5-8-6-7
  • 0-1-2-3-4-8-5-6-7
  • 0-1-2-3-8-4-5-6-7
  • 0-1-2-8-3-4-5-6-7
  • and so on...

11条回答
旧时光的记忆
2楼-- · 2019-01-01 01:41

You're looking for the permutations formula:

nPk = n!/(n-k)!

In your case, you have 9 entries and you want to choose all of them, that's 9P9 = 9! = 362880

You can find a PHP algorithm to permutate in recipe 4.26 of O'Reilly's "PHP Cookbook".

pc_permute(array(0, 1, 2, 3, 4, 5, 7, 8));

Copied in from O'Reilly:

function pc_permute($items, $perms = array( )) {
    if (empty($items)) { 
        print join(' ', $perms) . "\n";
    }  else {
        for ($i = count($items) - 1; $i >= 0; --$i) {
             $newitems = $items;
             $newperms = $perms;
             list($foo) = array_splice($newitems, $i, 1);
             array_unshift($newperms, $foo);
             pc_permute($newitems, $newperms);
         }
    }
}
查看更多
伤终究还是伤i
3楼-- · 2019-01-01 01:45

Since this question often comes up in Google Search results, here's a modified version of the accepted answer that returns all combinations in an array and passes them as a return value of the function.

function pc_permute($items, $perms = array( )) {
    if (empty($items)) {
        $return = array($perms);
    }  else {
        $return = array();
        for ($i = count($items) - 1; $i >= 0; --$i) {
             $newitems = $items;
             $newperms = $perms;
         list($foo) = array_splice($newitems, $i, 1);
             array_unshift($newperms, $foo);
             $return = array_merge($return, pc_permute($newitems, $newperms));
         }
    }
    return $return;
}

To use:

$value = array('1', '2', '3');
print_r(pc_permute($value));
查看更多
何处买醉
4楼-- · 2019-01-01 01:46

You're basically talking about permutations where both n and k are 9 so you'll have 9! different permutations; see this: http://en.wikipedia.org/wiki/Permutation.

查看更多
流年柔荑漫光年
5楼-- · 2019-01-01 01:48

Here is my proposal, hope a little bit clearer than accepted answer.

   function permutate($elements, $perm = array(), &$permArray = array())
{
    if(empty($elements))
    {
       array_push($permArray,$perm); return;
    }

    for($i=0;$i<=count($elements)-1;$i++)
    {
       array_push($perm,$elements[$i]);
       $tmp = $elements; array_splice($tmp,$i,1);
       permutate($tmp,$perm,$permArray);
       array_pop($perm);
    }

    return $permArray;
}

and usage:

$p = permutate(array('a','b','c'));
foreach($p as $perm)
    print join(",",$perm)."|\n";
查看更多
孤独总比滥情好
6楼-- · 2019-01-01 01:49

I've ported the Python itertools code listed here (using generators). The advantage over the solutions posted so far is that it allows you to specify r (permutation size).

function permutations($pool, $r = null) {
    $n = count($pool);

    if ($r == null) {
        $r = $n;
    }

    if ($r > $n) {
        return;
    }

    $indices = range(0, $n - 1);
    $cycles = range($n, $n - $r + 1, -1); // count down

    yield array_slice($pool, 0, $r);

    if ($n <= 0) {
        return;
    }

    while (true) {
        $exit_early = false;
        for ($i = $r;$i--;$i >= 0) {
            $cycles[$i]-= 1;
            if ($cycles[$i] == 0) {
                // Push whatever is at index $i to the end, move everything back
                if ($i < count($indices)) {
                    $removed = array_splice($indices, $i, 1);
                    array_push($indices, $removed[0]);
                }
                $cycles[$i] = $n - $i;
            } else {
                $j = $cycles[$i];
                // Swap indices $i & -$j.
                $i_val = $indices[$i];
                $neg_j_val = $indices[count($indices) - $j];
                $indices[$i] = $neg_j_val;
                $indices[count($indices) - $j] = $i_val;
                $result = [];
                $counter = 0;
                foreach ($indices as $indx) {
                    array_push($result, $pool[$indx]);
                    $counter++;
                    if ($counter == $r) break;
                }
                yield $result;
                $exit_early = true;
                break;
            }
        }
        if (!$exit_early) {
            break; // Outer while loop
        }
    }
}

It works for me, but no promises! Example usage:

$result = iterator_to_array(permutations([1, 2, 3, 4], 3));
foreach ($result as $row) {
    print implode(", ", $row) . "\n";
}
查看更多
登录 后发表回答