Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Permutations - all possible sets of numbers

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...
like image 357
Deele Avatar asked Mar 31 '11 22:03

Deele


People also ask

How do you find the permutations of a set of numbers?

To calculate the number of permutations, take the number of possibilities for each event and then multiply that number by itself X times, where X equals the number of events in the sequence. For example, with four-digit PINs, each digit can range from 0 to 9, giving us 10 possibilities for each digit.

How do you find all the possible combinations of numbers?

The formula for combinations is generally n! / (r! (n -- r)!), where n is the total number of possibilities to start and r is the number of selections made.

How many possible number of permutations are there?

There are 6 permutations of three different things. As the number of things (letters) increases, their permutations grow astronomically. For example, if twelve different things are permuted, then the number of their permutations is 479,001,600.

How many permutations are there of the set of n numbers?

Thus, the number of permutations of a set of n elements is n(n − 1)(n − 2)ททท2 · 1. This last expression is usually abbreviated n! and read “n factorial” or “factorial n” (except by some people who like to say “n shriek” or “n bang”).


10 Answers

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);
         }
    }
}
like image 179
yzxben Avatar answered Sep 28 '22 00:09

yzxben


Since PHP 5.5 you can use Generators. Generators save a lot of memory and are way faster (more than half compared to pc_permute()). So if you have any chance of having PHP 5.5 installed, you definitely want Generators. This snipped is ported from Python: https://stackoverflow.com/a/104436/3745311

function permutations(array $elements)
{
    if (count($elements) <= 1) {
        yield $elements;
    } else {
        foreach (permutations(array_slice($elements, 1)) as $permutation) {
            foreach (range(0, count($elements) - 1) as $i) {
                yield array_merge(
                    array_slice($permutation, 0, $i),
                    [$elements[0]],
                    array_slice($permutation, $i)
                );
            }
        }
    }
}

Sample usage:

$list = ['a', 'b', 'c'];

foreach (permutations($list) as $permutation) {
    echo implode(',', $permutation) . PHP_EOL;
}

Output:

a,b,c
b,a,c
b,c,a
a,c,b 
c,a,b
c,b,a
like image 39
spezifanta Avatar answered Sep 29 '22 00:09

spezifanta


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));
like image 31
dAngelov Avatar answered Sep 29 '22 00:09

dAngelov


I've something that You may like

function combination_number($k,$n){
    $n = intval($n);
    $k = intval($k);
    if ($k > $n){
        return 0;
    } elseif ($n == $k) {
        return 1;
    } else {
        if ($k >= $n - $k){
            $l = $k+1;
            for ($i = $l+1 ; $i <= $n ; $i++)
                $l *= $i;
            $m = 1;
            for ($i = 2 ; $i <= $n-$k ; $i++)
                $m *= $i;
        } else {
            $l = ($n-$k) + 1;
            for ($i = $l+1 ; $i <= $n ; $i++)
                $l *= $i;
            $m = 1;
            for ($i = 2 ; $i <= $k ; $i++)
                $m *= $i;            
        }
    }
    return $l/$m;
}

function array_combination($le, $set){

    $lk = combination_number($le, count($set));
    $ret = array_fill(0, $lk, array_fill(0, $le, '') );

    $temp = array();
    for ($i = 0 ; $i < $le ; $i++)
        $temp[$i] = $i;

    $ret[0] = $temp;

    for ($i = 1 ; $i < $lk ; $i++){
        if ($temp[$le-1] != count($set)-1){
            $temp[$le-1]++;
        } else {
            $od = -1;
            for ($j = $le-2 ; $j >= 0 ; $j--)
                if ($temp[$j]+1 != $temp[$j+1]){
                    $od = $j;
                    break;
                }
            if ($od == -1)
                break;
            $temp[$od]++;
            for ($j = $od+1 ; $j < $le ; $j++)    
                $temp[$j] = $temp[$od]+$j-$od;
        }
        $ret[$i] = $temp;
    }
    for ($i = 0 ; $i < $lk ; $i++)
        for ($j = 0 ; $j < $le ; $j++)
            $ret[$i][$j] = $set[$ret[$i][$j]];   

    return $ret;
}

Here is how to use it:

To get the number of combinations:

combination_number(3,10); // returns number of combinations of ten-elements set.

To get all possible combinations:

$mySet = array("A","B","C","D","E","F");
array_combination(3, $mySet); // returns all possible combinations of 3 elements of six-elements set.

Hope You make use of that.

like image 43
Piotr Salaciak Avatar answered Sep 30 '22 00:09

Piotr Salaciak


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";
}
like image 30
eddiewould Avatar answered Oct 01 '22 00:10

eddiewould


This is my version of class. This class builds and returns permutated array as result

class Permutation {
    private $result;

    public function getResult() {
        return $this->result;
    }

    public function permute($source, $permutated=array()) {
        if (empty($permutated)){
            $this->result = array();
        }
        if (empty($source)){
            $this->result[] = $permutated;
        } else {
            for($i=0; $i<count($source); $i++){
                $new_permutated = $permutated;
                $new_permutated[] = $source[$i];
                $new_source =    array_merge(array_slice($source,0,$i),array_slice($source,$i+1));
                $this->permute($new_source, $new_permutated);
            }
        }
        return $this;
    }
}

$arr = array(1,2,3,4,5);
$p = new Permutation();
print_r($p->permute($arr)->getResult());

The last three lines to test my class.

like image 35
Jeff_Alieffson Avatar answered Sep 29 '22 00:09

Jeff_Alieffson


This is a simple recursive function that prints all permutations (written in pseudocode)

function rec(n, k) {
    if (k == n) {
        for i = 0 to n-1
            print(perm[i], ' ');
        print('\n');
    }
    else {
        for i = 0 to n-1 {
            if (not used[i]) {
                used[i] = true;
                perm[k] = i;
                rec(n, k+1);
                used[i] = false;
            }
        }
    }
}

And it is called like this:

rec(9, 0);
like image 23
fdermishin Avatar answered Sep 29 '22 00:09

fdermishin


Lexicographical order. There is no recursion. Almost no limits for array length. There is no sort. It's running rather fast. It's easy to understand. Minus: it gives a notice, but you can add a condition to start compare with the second element or error_reporting(0).

$a = array(
1,
2,
3,
4,
5
 );
    $b = array_reverse($a);
    print_r($a);
   //here need "br"
  while ($a != $b)
{
foreach(array_reverse($a, true) as $k => $v)
    {
    if ($v < $a[$k + 1])
        {
        foreach(array_reverse($a, true) as $ka => $val)
            {
            if ($val > $v) break;
            }

        $ch = $a[$k];
        $a[$k] = $a[$ka];
        $a[$ka] = $ch;
        $c = array_slice($a, 0, $k + 1);
        print_r($a = array_merge($c, array_reverse(array_slice($a, $k + 1))));
        //here need "br"
        break;
        }
       }
      }
like image 25
dcc0 Avatar answered Sep 29 '22 00:09

dcc0


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.

like image 40
Argote Avatar answered Sep 29 '22 00:09

Argote


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";
like image 29
Jarek Avatar answered Sep 28 '22 00:09

Jarek