Related
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...
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);
}
}
}
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
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));
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.
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";
}
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.
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);
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;
}
}
}
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.
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";
//function call
print_r(combinations([1,2,3,4,5,6,7,8,9,10,11,12,13]));
/**
* #param $mainArray
* #param int $size - optional
* #param array $combinations - optional
* #return mixed
*/
function combinations($mainArray, $size = 3, $combinations = [])
{
if (empty($combinations)) {
$combinations = $mainArray;
}
if ($size == 1) {
return str_replace('-','',$combinations);;
}
$newCombination = array();
foreach ($mainArray as $key => $val){
foreach ($combinations as $char) {
if(in_array($val, explode('-', $char))){
continue;
}
$newCombination[] = $val . '-' . $char;
}
}
return combinations($mainArray, $size - 1, $newCombination);
}
//========================= Next solution ==================================
function sampling($chars, $size, $combinations = array()) {
# if it's the first iteration, the first set
# of combinations is the same as the set of characters
if (empty($combinations)) {
$combinations = $chars;
}
# we're done if we're at size 1
if ($size == 1) {
return $combinations;
}
# initialise array to put new values in
$new_combinations = array();
# loop through existing combinations and character set to create strings
foreach ($combinations as $combination) {
foreach ($chars as $char) {
$new_combinations[] = $combination .'-'. $char ;
}
}
# call same function again for the next iteration
return $this->sampling($chars, $size - 1, $new_combinations);
}
function array_has_dupes($array) {
return count($array) !== count(array_unique($array));
}
function total() {
// Generate ticket price
$arrfinal = array();
// combinations
$chars = array(1,2,3,4,5,6,7,8,9,10,11,12,13); // for 10 digits
$combinations = $this->sampling($chars, 3);
//print_r($combinations); //exit;
foreach($combinations as $key => $val)
{
$arr = explode('-', $val);//str_split($val);
if(!$this->array_has_dupes($arr)){
$arrfinal[] = str_replace('-', '', $val);
}
}
echo '<pre>'; print_r($arrfinal); echo '</pre>';
}
Simple solution using recursion
function filterElement($element){
if(is_array($element[0])){
return $element[0];
}
# base case
return $element;
}
function permutation($input, $path){
// base case 1
if(count($input) == 0){
return [$path];
}
$output = [];
foreach($input as $index => $num){ # 1, 2,3, 4
$copyPath = $path; # copy the path - []
$copyPath[] = $num; # append the number [1]
# remove the current number
$inputLocal = $input;
unset($inputLocal[$index]); # [2, 3, 4]
$permute = permutation($inputLocal, $copyPath); # call [2, 3, 4], [1]
# for all element find add to output
foreach($permute as $ele){
# filter ouput
$output[] = filterElement($ele);
}
}
return $output;
}
print_r(permutation([1,2,3,4], []));
output
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
[1] => Array
(
[0] => 1
[1] => 2
[2] => 4
[3] => 3
)
[2] => Array
(
[0] => 1
[1] => 3
[2] => 2
[3] => 4
)
[3] => Array
(
[0] => 1
[1] => 3
[2] => 4
[3] => 2
)
[4] => Array
(
[0] => 1
[1] => 4
[2] => 2
[3] => 3
)
[5] => Array
(
[0] => 1
[1] => 4
[2] => 3
[3] => 2
)
[6] => Array
(
[0] => 2
[1] => 1
[2] => 3
[3] => 4
)
[7] => Array
(
[0] => 2
[1] => 1
[2] => 4
[3] => 3
)
[8] => Array
(
[0] => 2
[1] => 3
[2] => 1
[3] => 4
)
[9] => Array
(
[0] => 2
[1] => 3
[2] => 4
[3] => 1
)
[10] => Array
(
[0] => 2
[1] => 4
[2] => 1
[3] => 3
)
[11] => Array
(
[0] => 2
[1] => 4
[2] => 3
[3] => 1
)
[12] => Array
(
[0] => 3
[1] => 1
[2] => 2
[3] => 4
)
[13] => Array
(
[0] => 3
[1] => 1
[2] => 4
[3] => 2
)
[14] => Array
(
[0] => 3
[1] => 2
[2] => 1
[3] => 4
)
[15] => Array
(
[0] => 3
[1] => 2
[2] => 4
[3] => 1
)
[16] => Array
(
[0] => 3
[1] => 4
[2] => 1
[3] => 2
)
[17] => Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
)
[18] => Array
(
[0] => 4
[1] => 1
[2] => 2
[3] => 3
)
[19] => Array
(
[0] => 4
[1] => 1
[2] => 3
[3] => 2
)
[20] => Array
(
[0] => 4
[1] => 2
[2] => 1
[3] => 3
)
[21] => Array
(
[0] => 4
[1] => 2
[2] => 3
[3] => 1
)
[22] => Array
(
[0] => 4
[1] => 3
[2] => 1
[3] => 2
)
[23] => Array
(
[0] => 4
[1] => 3
[2] => 2
[3] => 1
)
)
I have array value like this :
$src = array(3,15,16,17,18,20,25,7);
How can i split it into :
array(
[0] => 3,
[1] => array([0] => 15, [1] => 18),//when value is range get start and end
[2] => 20,
[3] => 25,
[4] =>
);
Check this code. If your sequence/range difference is based on only next numbers, then this code would work for you.
<?php
$src = array(3,15,16,17,18,20,25,7);
$tot = count($src);
$resarr = array();
$st = $ed = '';
for($i=0;$i<$tot;$i++){
if($st==''){
if(isset($src[$i+1]) && $src[$i+1] == $src[$i]+1){
$st = $src[$i];
}
}
else{
if(!isset($src[$i+1]) || $src[$i+1] != $src[$i]+1){
$ed=$src[$i];
}
}
if($st=='' && $ed==''){
$resarr[] = $src[$i];
}
elseif($st!='' && $ed!=''){
$resarr[] = array($st,$ed);
$st = $ed='';
}
}
print_r($src);
echo "<pre>";print_r($resarr);echo "</pre>";
?>
Also phpfiddle example is here http://phpfiddle.org/lite/code/k7c4-wvdg. Keep practice write your own logic.
// Make copy of array with shifting to one item.
// And, to save array length, add one element to the end of the array.
// It can be any number, but not continue sequence.
// I add the last item of source array
$src1 = $src;
array_shift($src1);
array_push($src1,end($src));
// Then subtract corresponding items of array
$temp = array_map(function ($i, $j) { return $j-$i; }, $src, $src1);
// Look at arrays
// $src 3, 15, 16, 17, 18, 20, 25, 7
// $temp 12, 1, 1, 1, 2, 5, -18, 0,
// As you can see, all elements of sequences, but the last, has 1 in `temp` array.
// Therefore, we just need to collect the result
$sarr = false;
$result = array();
for($i=0; $i<count($src); $i++) {
if($temp[$i] == 1) {
if(! $sarr) {
$sarr = $src[$i];
}
}
else {
if(! $sarr) {
$result[] = $src[$i];
}
else {
$result[] = [$sarr, $src[$i]];
$sarr = false;
}
}
}
print_r($result);
Test it there
I added some values just to cover edge cases. Comments explain.
<?php
$src = array(3,4,15,16,17,18,20,25,7,8);
$res = [];
$start = null;
//Rather than make a counter use a for loop
for($i=0; $i < count($src); $i++){
//Make sure i+1 is not bigger than array
//If current index value + 1
//Euqals the next index value we have a range
if($i+1 < count($src) && $src[$i]+1 == $src[$i+1]){
if($start === null){
$start = $i;
}
//Once the range is over we can use the current index as end
} elseif($start !== null){
$res[] = array($src[$start], $src[$i]);
$start = null;
$end = null;
//There was never a range.
} else {
$res[] = $src[$i];
}
}
echo "<pre>";
print_r($res);
Results:
Array
(
[0] => Array
(
[0] => 3
[1] => 4
)
[1] => Array
(
[0] => 15
[1] => 18
)
[2] => 20
[3] => 25
[4] => Array
(
[0] => 7
[1] => 8
)
)
I have something like that:
$n = 2;
$items = array();
$result = array(); // new array with random items
$random_items = array_rand( $items, $n );
for( $f=0; $f<=$n; $f++ ) {
$result[] = $items[$random_items[$f]];
}
$items is sth like
Array ( [0] => file1.jpg [1] => file2.png [2] => file3.jpg ... and so on )
This is working OK... but if I set $n to 1 then the script is not working or working incorrectly!
If $n == 2 (or more) the result array have last element's value empty
Array ( [0] => 20141125-17826a4b34.png [1] => 20141125-27fe57561d.jpg [2] => )
If $n == 1 (exactly) the result array is like
Array ( [0] => [1] => )
The result array should be the same format as items array but only with $n random items.
Thanks in advance!
Working
if( $n > 1 ) {
for( $f=0; $f<$n; $f++ ) {
$result[] = $items[$random_items[$f]];
}
}
elseif( $n == 1 ) {
$result[0] = $items[$random_items];
}
You should $f < $n instead of $f <= $n
for( $f=0; $f < $n; $f++ ) {
$result[] = $items[$random_items[$f]];
}
Because, when you're using $f <= $n its running up to 0,1 (when, $n = 1) OR 0,1,2 (when $n = 2) and you're missing the last indexed element.
When picking only one entry, array_rand() returns the key for a random
entry(not array).Otherwise, an array of keys for the random entries is returned.
So, This means, when you're using $n = 1, then $random_items is just a value(not array). eg.
for $n = 1, $random_items = 4;
but for $n >= 2, $random_items = [1, 6, 3, 6];
I have an array like so:
Array ( [0] => 0 [1] => 0 [2] => 0 );
there are 3 elements (3 integers) and I want them to increment from 0 to 36;
I understand that the best way for this is recursion because each element has to be checked to see if it is at the maximum ( 36 ) and if it is, it sets the last element to 0 and increments the previous.
so my array basically wants to go like:
Array ( [0] => 0 [1] => 0 [2] => 0 );
Array ( [0] => 0 [1] => 0 [2] => 1 );
Array ( [0] => 0 [1] => 0 [2] => 2 );
...
Array ( [0] => 0 [1] => 0 [2] => 36 );
Array ( [0] => 0 [1] => 1 [2] => 0 );
Array ( [0] => 0 [1] => 1 [2] => 1 );
....
Array ( [0] => 0 [1] => 1 [2] => 36 );
Array ( [0] => 0 [1] => 2 [2] => 0 );
ETC ETC ETC
But I've got no idea how to do this recursively!
However the solution also needs to work for 4 elements and 5 elements and 6 etc etc!
Can anybody give me some direction?
Similar to Timurs answer, however slightly more efficient and takes a variable base.
$array = array(0, 0, 0);
function bloop(&$array, $amount, $base = 37)
{
$i = count($array) - 1;
while ($i >= 0) {
$array[$i] = $amount % $base;
$amount = ($amount - $array[$i--]) / $base;
}
}
bloop($array, (37 * 37 * 2) + (37 * 5) + 8); // 2, 5, 8
var_dump($array);
If you just want a base-37 number, consider using base_convert instead.
$limit = 36;
$step = 1;
$array = array ( 0 , 0 , 0 );
function increment( array $array , $limit , $step ) {
$result = $array = array_values( $array );
while( count( array_keys( $result , $limit ) ) != count( $array ) ) {
for( $i = 1 ; $i <= count( $result ) ; $i++ ) {
while( $result[ count( $result )-$i ] < $limit ) {
$result[ count( $result )-$i ] += $step;
}
}
}
return $result;
}
var_dump( increment( $array , $limit , $step ) );
function fill($limit){
$ret = array();
while($i<=$limit){
while($j<=$limit){
while($k<=$limit){
$ret[] = array($i,$j,$k);
print_r($a);
$k++;
}
$j++;
}
$i++;
}
return $ret;
}
fill(36);
function increment(&$array,$num){
$plus = $num;
for( $i=count($array)-1;$i>=0;$i-- ){
$array[$i] += $plus;
if( $array[$i]>36 ){
$tmp = $array[$i]%37;
$plus = ($array[$i]-$tmp)/37;
$array[$i] = $tmp;
}else{
break;
}
}
}
// init array
$array = array( 0,0,0 );
// increment 100 times
increment($array,100);
var_dump($array);
what about this??
<?php
$arr = array(0=>0,2=>0);
foreach (range(0,36) as $f )
{
echo "<pre>";print_r(array_pad(array($f),3,0));
echo "<pre>";print_r(array_pad(array($f),-3,0));
$arr_n = $arr+array(1=>$f);
ksort($arr_n);
echo "<pre>"; print_r($arr_n);
}
?>
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...
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);
}
}
}
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
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));
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.
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";
}
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.
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);
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;
}
}
}
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.
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";
//function call
print_r(combinations([1,2,3,4,5,6,7,8,9,10,11,12,13]));
/**
* #param $mainArray
* #param int $size - optional
* #param array $combinations - optional
* #return mixed
*/
function combinations($mainArray, $size = 3, $combinations = [])
{
if (empty($combinations)) {
$combinations = $mainArray;
}
if ($size == 1) {
return str_replace('-','',$combinations);;
}
$newCombination = array();
foreach ($mainArray as $key => $val){
foreach ($combinations as $char) {
if(in_array($val, explode('-', $char))){
continue;
}
$newCombination[] = $val . '-' . $char;
}
}
return combinations($mainArray, $size - 1, $newCombination);
}
//========================= Next solution ==================================
function sampling($chars, $size, $combinations = array()) {
# if it's the first iteration, the first set
# of combinations is the same as the set of characters
if (empty($combinations)) {
$combinations = $chars;
}
# we're done if we're at size 1
if ($size == 1) {
return $combinations;
}
# initialise array to put new values in
$new_combinations = array();
# loop through existing combinations and character set to create strings
foreach ($combinations as $combination) {
foreach ($chars as $char) {
$new_combinations[] = $combination .'-'. $char ;
}
}
# call same function again for the next iteration
return $this->sampling($chars, $size - 1, $new_combinations);
}
function array_has_dupes($array) {
return count($array) !== count(array_unique($array));
}
function total() {
// Generate ticket price
$arrfinal = array();
// combinations
$chars = array(1,2,3,4,5,6,7,8,9,10,11,12,13); // for 10 digits
$combinations = $this->sampling($chars, 3);
//print_r($combinations); //exit;
foreach($combinations as $key => $val)
{
$arr = explode('-', $val);//str_split($val);
if(!$this->array_has_dupes($arr)){
$arrfinal[] = str_replace('-', '', $val);
}
}
echo '<pre>'; print_r($arrfinal); echo '</pre>';
}
Simple solution using recursion
function filterElement($element){
if(is_array($element[0])){
return $element[0];
}
# base case
return $element;
}
function permutation($input, $path){
// base case 1
if(count($input) == 0){
return [$path];
}
$output = [];
foreach($input as $index => $num){ # 1, 2,3, 4
$copyPath = $path; # copy the path - []
$copyPath[] = $num; # append the number [1]
# remove the current number
$inputLocal = $input;
unset($inputLocal[$index]); # [2, 3, 4]
$permute = permutation($inputLocal, $copyPath); # call [2, 3, 4], [1]
# for all element find add to output
foreach($permute as $ele){
# filter ouput
$output[] = filterElement($ele);
}
}
return $output;
}
print_r(permutation([1,2,3,4], []));
output
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
[1] => Array
(
[0] => 1
[1] => 2
[2] => 4
[3] => 3
)
[2] => Array
(
[0] => 1
[1] => 3
[2] => 2
[3] => 4
)
[3] => Array
(
[0] => 1
[1] => 3
[2] => 4
[3] => 2
)
[4] => Array
(
[0] => 1
[1] => 4
[2] => 2
[3] => 3
)
[5] => Array
(
[0] => 1
[1] => 4
[2] => 3
[3] => 2
)
[6] => Array
(
[0] => 2
[1] => 1
[2] => 3
[3] => 4
)
[7] => Array
(
[0] => 2
[1] => 1
[2] => 4
[3] => 3
)
[8] => Array
(
[0] => 2
[1] => 3
[2] => 1
[3] => 4
)
[9] => Array
(
[0] => 2
[1] => 3
[2] => 4
[3] => 1
)
[10] => Array
(
[0] => 2
[1] => 4
[2] => 1
[3] => 3
)
[11] => Array
(
[0] => 2
[1] => 4
[2] => 3
[3] => 1
)
[12] => Array
(
[0] => 3
[1] => 1
[2] => 2
[3] => 4
)
[13] => Array
(
[0] => 3
[1] => 1
[2] => 4
[3] => 2
)
[14] => Array
(
[0] => 3
[1] => 2
[2] => 1
[3] => 4
)
[15] => Array
(
[0] => 3
[1] => 2
[2] => 4
[3] => 1
)
[16] => Array
(
[0] => 3
[1] => 4
[2] => 1
[3] => 2
)
[17] => Array
(
[0] => 3
[1] => 4
[2] => 2
[3] => 1
)
[18] => Array
(
[0] => 4
[1] => 1
[2] => 2
[3] => 3
)
[19] => Array
(
[0] => 4
[1] => 1
[2] => 3
[3] => 2
)
[20] => Array
(
[0] => 4
[1] => 2
[2] => 1
[3] => 3
)
[21] => Array
(
[0] => 4
[1] => 2
[2] => 3
[3] => 1
)
[22] => Array
(
[0] => 4
[1] => 3
[2] => 1
[3] => 2
)
[23] => Array
(
[0] => 4
[1] => 3
[2] => 2
[3] => 1
)
)