Text fragment permutation in PHP? [duplicate] - php

Given a PHP array of strings, e.g.:
['peter', 'paul', 'mary']
How to generate all possible permutations of elements of this array? i.e.:
peter-paul-mary
peter-mary-paul
paul-peter-mary
paul-mary-peter
mary-peter-paul
mary-paul-peter

function pc_permute($items, $perms = array()) {
if (empty($items)) {
echo join(' ', $perms) . "<br />";
} 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);
}
}
}
$arr = array('peter', 'paul', 'mary');
pc_permute($arr);
or
function pc_next_permutation($p, $size) {
// slide down the array looking for where we're smaller than the next guy
for ($i = $size - 1; $p[$i] >= $p[$i+1]; --$i) { }
// if this doesn't occur, we've finished our permutations
// the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
if ($i == -1) { return false; }
// slide down the array looking for a bigger number than what we found before
for ($j = $size; $p[$j] <= $p[$i]; --$j) { }
// swap them
$tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
// now reverse the elements in between by swapping the ends
for (++$i, $j = $size; $i < $j; ++$i, --$j) {
$tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
}
return $p;
}
$set = split(' ', 'she sells seashells'); // like array('she', 'sells', 'seashells')
$size = count($set) - 1;
$perm = range(0, $size);
$j = 0;
do {
foreach ($perm as $i) { $perms[$j][] = $set[$i]; }
} while ($perm = pc_next_permutation($perm, $size) and ++$j);
foreach ($perms as $p) {
print join(' ', $p) . "\n";
}
http://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm

This does what you need, in place, i.e. without allocating any additional memory. It stores the resulting permutations the $results array. I am pretty confident that this is the fasted way to solve the task.
<?php
function computePermutations($array) {
$result = [];
$recurse = function($array, $start_i = 0) use (&$result, &$recurse) {
if ($start_i === count($array)-1) {
array_push($result, $array);
}
for ($i = $start_i; $i < count($array); $i++) {
//Swap array value at $i and $start_i
$t = $array[$i]; $array[$i] = $array[$start_i]; $array[$start_i] = $t;
//Recurse
$recurse($array, $start_i + 1);
//Restore old order
$t = $array[$i]; $array[$i] = $array[$start_i]; $array[$start_i] = $t;
}
};
$recurse($array);
return $result;
}
$results = computePermutations(array('foo', 'bar', 'baz'));
print_r($results);
This works in PHP>5.4. I used a anonymous function for recursion to keep the main function's interface clean.

I needed something similar and found this post while looking. Landed up writing the following which does the job.
With 8 items it works fairly quickly (a bit quicker than the examples I found online), but go beyond that and the run time ramps up rapidly. If you only need to output the results it could be made quicker and the memory use reduced massively.
print_r(AllPermutations(array('peter', 'paul', 'mary')));
function AllPermutations($InArray, $InProcessedArray = array())
{
$ReturnArray = array();
foreach($InArray as $Key=>$value)
{
$CopyArray = $InProcessedArray;
$CopyArray[$Key] = $value;
$TempArray = array_diff_key($InArray, $CopyArray);
if (count($TempArray) == 0)
{
$ReturnArray[] = $CopyArray;
}
else
{
$ReturnArray = array_merge($ReturnArray, AllPermutations($TempArray, $CopyArray));
}
}
return $ReturnArray;
}
Note that the number of permutations is the factorial of the number of items in the array. For 3 items there are 6 permutations, for 4 there are 24, for 5 there are 120, for 6 there are 720, etc.
EDIT
Came back to have a look at this and done some revisions.
Below is an improved version of this function, which uses less storage and is quicker (quicker than other solutions I have seen).
It takes the return array as a parameter, passing it through by reference. This reduces the amount of duplication of data as it runs through.
function AllPermutations($InArray, &$ReturnArray = array(), $InProcessedArray = array())
{
if (count($InArray) == 1)
{
$ReturnArray[] = array_merge($InProcessedArray, $InArray);
}
else
{
foreach($InArray as $Key=>$value)
{
$CopyArray = $InArray;
unset($CopyArray[$Key]);
AllPermutations2($CopyArray, $ReturnArray, array_merge($InProcessedArray, array($Key=>$value)));
}
}
}

I expanded a bit on the answer of Jack
function pc_permute($items, $perms = [],&$ret = []) {
if (empty($items)) {
$ret[] = $perms;
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
$this->pc_permute($newitems, $newperms,$ret);
}
}
return $ret;
}
This will actually return an array with all possible permutations.
$options = ['startx','starty','startz','endx','endy','endz'];
$x = $this->pc_permute($options);
var_dump($x);
[0]=>
array(6) {
[0]=>
string(6) "startx"
[1]=>
string(6) "starty"
[2]=>
string(6) "startz"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[1]=>
array(6) {
[0]=>
string(6) "starty"
[1]=>
string(6) "startx"
[2]=>
string(6) "startz"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[2]=>
array(6) {
[0]=>
string(6) "startx"
[1]=>
string(6) "startz"
[2]=>
string(6) "starty"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[3]=>
array(6) {
[0]=>
string(6) "startz"
[1]=>
string(6) "startx"
[2]=>
string(6) "starty"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[4]=>
array(6) {
[0]=>
string(6) "starty"
[1]=>
string(6) "startz"
[2]=>
string(6) "startx"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[5]=>
array(6) {
[0]=>
string(6) "startz"
[1]=>
string(6) "starty"
[2]=>
string(6) "startx"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[6]=> ................ a lot more
I found it a bit more usefull to get an array back instead of a string. Then it's up to the using application how to handle the resutls(to join them, or something else)

Simple version with recursion and no artificial extra arguments:
function permuteArray(array $input) {
$input = array_values($input);
// permutation of 1 value is the same value
if (count($input) === 1) {
return array($input);
}
// to permute multiple values, pick a value to put in the front and
// permute the rest; repeat this with all values of the original array
$result = [];
for ($i = 0; $i < count($input); $i++) {
$copy = $input;
$value = array_splice($copy, $i, 1);
foreach (permuteArray($copy) as $permutation) {
array_unshift($permutation, $value[0]);
$result[] = $permutation;
}
}
return $result;
}
This algorithm is nice and instructive how you would do it on paper, but otherwise very inefficient as it calculates same permutations multiple times. Not to say that it is very impractical for calculating permutations of larger arrays as the space and number of calculations grow exponentially.

Recursive function to get all permutations of an array.
Call getPermutations($arr) to get an array of arrays with all the permutations.
function getPermutations ($arr)
{
assert (!empty($arr));
if (count($arr)==1)
{
return [$arr];
}
$first=array_shift($arr);
$permutations=getPermutations($arr);
$result=[];
foreach ($permutations as $permutation)
{
$result=array_merge($result, addElementInAllPositions($permutation, $first));
}
return $result;
}
function addElementInAllPositions ($arr, $element)
{
$i=0;
$result=[];
while ($i<=count($arr))
{
$result[]=array_merge(array_slice($arr,0,$i), [$element], array_slice($arr, $i));
$i++;
}
return $result;
}

Here is another variant based on this article: https://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm
public static function get_array_orders( $arr ) {
$arr = array_values( $arr ); // Make sure array begins from 0.
$size = count( $arr ) - 1;
$order = range( 0, $size );
$i = 0;
$orders = [];
do {
foreach ( $order as $key ) {
$orders[ $i ][] = $arr[ $key ];
}
$i ++;
} while ( $order = self::get_next_array_order( $order, $size ) );
return $orders;
}
protected static function get_next_array_order( $order, $size ) {
// slide down the array looking for where we're smaller than the next guy
$i = $size - 1;
while ( isset( $order[ $i ] ) && $order[ $i ] >= $order[ $i + 1 ] ) {
$i --;
}
// if this doesn't occur, we've finished our permutations, the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
if ( $i == - 1 ) {
return false;
}
// slide down the array looking for a bigger number than what we found before
$j = $size;
while( $order[ $j ] <= $order[ $i ] ){
$j--;
}
// swap them
$tmp = $order[ $i ];
$order[ $i ] = $order[ $j ];
$order[ $j ] = $tmp;
// now reverse the elements in between by swapping the ends
for ( ++ $i, $j = $size; $i < $j; ++ $i, -- $j ) {
$tmp = $order[ $i ];
$order[ $i ] = $order[ $j ];
$order[ $j ] = $tmp;
}
return $order;
}
Example:
$langs = ['en', 'fr', 'ru'];
$orders = self::get_array_orders( $langs );
print_r($orders);
Outputs:
Array (
[0] => Array
(
[0] => en
[1] => fr
[2] => ru
)
[1] => Array
(
[0] => en
[1] => ru
[2] => fr
)
[2] => Array
(
[0] => fr
[1] => en
[2] => ru
)
[3] => Array
(
[0] => fr
[1] => ru
[2] => en
)
[4] => Array
(
[0] => ru
[1] => en
[2] => fr
)
[5] => Array
(
[0] => ru
[1] => fr
[2] => en
)
)

Related

Generating all combinations of an array of search keywords without fixed size in php [duplicate]

Given a PHP array of strings, e.g.:
['peter', 'paul', 'mary']
How to generate all possible permutations of elements of this array? i.e.:
peter-paul-mary
peter-mary-paul
paul-peter-mary
paul-mary-peter
mary-peter-paul
mary-paul-peter
function pc_permute($items, $perms = array()) {
if (empty($items)) {
echo join(' ', $perms) . "<br />";
} 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);
}
}
}
$arr = array('peter', 'paul', 'mary');
pc_permute($arr);
or
function pc_next_permutation($p, $size) {
// slide down the array looking for where we're smaller than the next guy
for ($i = $size - 1; $p[$i] >= $p[$i+1]; --$i) { }
// if this doesn't occur, we've finished our permutations
// the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
if ($i == -1) { return false; }
// slide down the array looking for a bigger number than what we found before
for ($j = $size; $p[$j] <= $p[$i]; --$j) { }
// swap them
$tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
// now reverse the elements in between by swapping the ends
for (++$i, $j = $size; $i < $j; ++$i, --$j) {
$tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
}
return $p;
}
$set = split(' ', 'she sells seashells'); // like array('she', 'sells', 'seashells')
$size = count($set) - 1;
$perm = range(0, $size);
$j = 0;
do {
foreach ($perm as $i) { $perms[$j][] = $set[$i]; }
} while ($perm = pc_next_permutation($perm, $size) and ++$j);
foreach ($perms as $p) {
print join(' ', $p) . "\n";
}
http://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm
This does what you need, in place, i.e. without allocating any additional memory. It stores the resulting permutations the $results array. I am pretty confident that this is the fasted way to solve the task.
<?php
function computePermutations($array) {
$result = [];
$recurse = function($array, $start_i = 0) use (&$result, &$recurse) {
if ($start_i === count($array)-1) {
array_push($result, $array);
}
for ($i = $start_i; $i < count($array); $i++) {
//Swap array value at $i and $start_i
$t = $array[$i]; $array[$i] = $array[$start_i]; $array[$start_i] = $t;
//Recurse
$recurse($array, $start_i + 1);
//Restore old order
$t = $array[$i]; $array[$i] = $array[$start_i]; $array[$start_i] = $t;
}
};
$recurse($array);
return $result;
}
$results = computePermutations(array('foo', 'bar', 'baz'));
print_r($results);
This works in PHP>5.4. I used a anonymous function for recursion to keep the main function's interface clean.
I needed something similar and found this post while looking. Landed up writing the following which does the job.
With 8 items it works fairly quickly (a bit quicker than the examples I found online), but go beyond that and the run time ramps up rapidly. If you only need to output the results it could be made quicker and the memory use reduced massively.
print_r(AllPermutations(array('peter', 'paul', 'mary')));
function AllPermutations($InArray, $InProcessedArray = array())
{
$ReturnArray = array();
foreach($InArray as $Key=>$value)
{
$CopyArray = $InProcessedArray;
$CopyArray[$Key] = $value;
$TempArray = array_diff_key($InArray, $CopyArray);
if (count($TempArray) == 0)
{
$ReturnArray[] = $CopyArray;
}
else
{
$ReturnArray = array_merge($ReturnArray, AllPermutations($TempArray, $CopyArray));
}
}
return $ReturnArray;
}
Note that the number of permutations is the factorial of the number of items in the array. For 3 items there are 6 permutations, for 4 there are 24, for 5 there are 120, for 6 there are 720, etc.
EDIT
Came back to have a look at this and done some revisions.
Below is an improved version of this function, which uses less storage and is quicker (quicker than other solutions I have seen).
It takes the return array as a parameter, passing it through by reference. This reduces the amount of duplication of data as it runs through.
function AllPermutations($InArray, &$ReturnArray = array(), $InProcessedArray = array())
{
if (count($InArray) == 1)
{
$ReturnArray[] = array_merge($InProcessedArray, $InArray);
}
else
{
foreach($InArray as $Key=>$value)
{
$CopyArray = $InArray;
unset($CopyArray[$Key]);
AllPermutations2($CopyArray, $ReturnArray, array_merge($InProcessedArray, array($Key=>$value)));
}
}
}
I expanded a bit on the answer of Jack
function pc_permute($items, $perms = [],&$ret = []) {
if (empty($items)) {
$ret[] = $perms;
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
$this->pc_permute($newitems, $newperms,$ret);
}
}
return $ret;
}
This will actually return an array with all possible permutations.
$options = ['startx','starty','startz','endx','endy','endz'];
$x = $this->pc_permute($options);
var_dump($x);
[0]=>
array(6) {
[0]=>
string(6) "startx"
[1]=>
string(6) "starty"
[2]=>
string(6) "startz"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[1]=>
array(6) {
[0]=>
string(6) "starty"
[1]=>
string(6) "startx"
[2]=>
string(6) "startz"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[2]=>
array(6) {
[0]=>
string(6) "startx"
[1]=>
string(6) "startz"
[2]=>
string(6) "starty"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[3]=>
array(6) {
[0]=>
string(6) "startz"
[1]=>
string(6) "startx"
[2]=>
string(6) "starty"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[4]=>
array(6) {
[0]=>
string(6) "starty"
[1]=>
string(6) "startz"
[2]=>
string(6) "startx"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[5]=>
array(6) {
[0]=>
string(6) "startz"
[1]=>
string(6) "starty"
[2]=>
string(6) "startx"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[6]=> ................ a lot more
I found it a bit more usefull to get an array back instead of a string. Then it's up to the using application how to handle the resutls(to join them, or something else)
Simple version with recursion and no artificial extra arguments:
function permuteArray(array $input) {
$input = array_values($input);
// permutation of 1 value is the same value
if (count($input) === 1) {
return array($input);
}
// to permute multiple values, pick a value to put in the front and
// permute the rest; repeat this with all values of the original array
$result = [];
for ($i = 0; $i < count($input); $i++) {
$copy = $input;
$value = array_splice($copy, $i, 1);
foreach (permuteArray($copy) as $permutation) {
array_unshift($permutation, $value[0]);
$result[] = $permutation;
}
}
return $result;
}
This algorithm is nice and instructive how you would do it on paper, but otherwise very inefficient as it calculates same permutations multiple times. Not to say that it is very impractical for calculating permutations of larger arrays as the space and number of calculations grow exponentially.
Recursive function to get all permutations of an array.
Call getPermutations($arr) to get an array of arrays with all the permutations.
function getPermutations ($arr)
{
assert (!empty($arr));
if (count($arr)==1)
{
return [$arr];
}
$first=array_shift($arr);
$permutations=getPermutations($arr);
$result=[];
foreach ($permutations as $permutation)
{
$result=array_merge($result, addElementInAllPositions($permutation, $first));
}
return $result;
}
function addElementInAllPositions ($arr, $element)
{
$i=0;
$result=[];
while ($i<=count($arr))
{
$result[]=array_merge(array_slice($arr,0,$i), [$element], array_slice($arr, $i));
$i++;
}
return $result;
}
Here is another variant based on this article: https://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm
public static function get_array_orders( $arr ) {
$arr = array_values( $arr ); // Make sure array begins from 0.
$size = count( $arr ) - 1;
$order = range( 0, $size );
$i = 0;
$orders = [];
do {
foreach ( $order as $key ) {
$orders[ $i ][] = $arr[ $key ];
}
$i ++;
} while ( $order = self::get_next_array_order( $order, $size ) );
return $orders;
}
protected static function get_next_array_order( $order, $size ) {
// slide down the array looking for where we're smaller than the next guy
$i = $size - 1;
while ( isset( $order[ $i ] ) && $order[ $i ] >= $order[ $i + 1 ] ) {
$i --;
}
// if this doesn't occur, we've finished our permutations, the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
if ( $i == - 1 ) {
return false;
}
// slide down the array looking for a bigger number than what we found before
$j = $size;
while( $order[ $j ] <= $order[ $i ] ){
$j--;
}
// swap them
$tmp = $order[ $i ];
$order[ $i ] = $order[ $j ];
$order[ $j ] = $tmp;
// now reverse the elements in between by swapping the ends
for ( ++ $i, $j = $size; $i < $j; ++ $i, -- $j ) {
$tmp = $order[ $i ];
$order[ $i ] = $order[ $j ];
$order[ $j ] = $tmp;
}
return $order;
}
Example:
$langs = ['en', 'fr', 'ru'];
$orders = self::get_array_orders( $langs );
print_r($orders);
Outputs:
Array (
[0] => Array
(
[0] => en
[1] => fr
[2] => ru
)
[1] => Array
(
[0] => en
[1] => ru
[2] => fr
)
[2] => Array
(
[0] => fr
[1] => en
[2] => ru
)
[3] => Array
(
[0] => fr
[1] => ru
[2] => en
)
[4] => Array
(
[0] => ru
[1] => en
[2] => fr
)
[5] => Array
(
[0] => ru
[1] => fr
[2] => en
)
)

Calculate all possible combinations in array and display them in table php [duplicate]

Given a PHP array of strings, e.g.:
['peter', 'paul', 'mary']
How to generate all possible permutations of elements of this array? i.e.:
peter-paul-mary
peter-mary-paul
paul-peter-mary
paul-mary-peter
mary-peter-paul
mary-paul-peter
function pc_permute($items, $perms = array()) {
if (empty($items)) {
echo join(' ', $perms) . "<br />";
} 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);
}
}
}
$arr = array('peter', 'paul', 'mary');
pc_permute($arr);
or
function pc_next_permutation($p, $size) {
// slide down the array looking for where we're smaller than the next guy
for ($i = $size - 1; $p[$i] >= $p[$i+1]; --$i) { }
// if this doesn't occur, we've finished our permutations
// the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
if ($i == -1) { return false; }
// slide down the array looking for a bigger number than what we found before
for ($j = $size; $p[$j] <= $p[$i]; --$j) { }
// swap them
$tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
// now reverse the elements in between by swapping the ends
for (++$i, $j = $size; $i < $j; ++$i, --$j) {
$tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
}
return $p;
}
$set = split(' ', 'she sells seashells'); // like array('she', 'sells', 'seashells')
$size = count($set) - 1;
$perm = range(0, $size);
$j = 0;
do {
foreach ($perm as $i) { $perms[$j][] = $set[$i]; }
} while ($perm = pc_next_permutation($perm, $size) and ++$j);
foreach ($perms as $p) {
print join(' ', $p) . "\n";
}
http://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm
This does what you need, in place, i.e. without allocating any additional memory. It stores the resulting permutations the $results array. I am pretty confident that this is the fasted way to solve the task.
<?php
function computePermutations($array) {
$result = [];
$recurse = function($array, $start_i = 0) use (&$result, &$recurse) {
if ($start_i === count($array)-1) {
array_push($result, $array);
}
for ($i = $start_i; $i < count($array); $i++) {
//Swap array value at $i and $start_i
$t = $array[$i]; $array[$i] = $array[$start_i]; $array[$start_i] = $t;
//Recurse
$recurse($array, $start_i + 1);
//Restore old order
$t = $array[$i]; $array[$i] = $array[$start_i]; $array[$start_i] = $t;
}
};
$recurse($array);
return $result;
}
$results = computePermutations(array('foo', 'bar', 'baz'));
print_r($results);
This works in PHP>5.4. I used a anonymous function for recursion to keep the main function's interface clean.
I needed something similar and found this post while looking. Landed up writing the following which does the job.
With 8 items it works fairly quickly (a bit quicker than the examples I found online), but go beyond that and the run time ramps up rapidly. If you only need to output the results it could be made quicker and the memory use reduced massively.
print_r(AllPermutations(array('peter', 'paul', 'mary')));
function AllPermutations($InArray, $InProcessedArray = array())
{
$ReturnArray = array();
foreach($InArray as $Key=>$value)
{
$CopyArray = $InProcessedArray;
$CopyArray[$Key] = $value;
$TempArray = array_diff_key($InArray, $CopyArray);
if (count($TempArray) == 0)
{
$ReturnArray[] = $CopyArray;
}
else
{
$ReturnArray = array_merge($ReturnArray, AllPermutations($TempArray, $CopyArray));
}
}
return $ReturnArray;
}
Note that the number of permutations is the factorial of the number of items in the array. For 3 items there are 6 permutations, for 4 there are 24, for 5 there are 120, for 6 there are 720, etc.
EDIT
Came back to have a look at this and done some revisions.
Below is an improved version of this function, which uses less storage and is quicker (quicker than other solutions I have seen).
It takes the return array as a parameter, passing it through by reference. This reduces the amount of duplication of data as it runs through.
function AllPermutations($InArray, &$ReturnArray = array(), $InProcessedArray = array())
{
if (count($InArray) == 1)
{
$ReturnArray[] = array_merge($InProcessedArray, $InArray);
}
else
{
foreach($InArray as $Key=>$value)
{
$CopyArray = $InArray;
unset($CopyArray[$Key]);
AllPermutations2($CopyArray, $ReturnArray, array_merge($InProcessedArray, array($Key=>$value)));
}
}
}
I expanded a bit on the answer of Jack
function pc_permute($items, $perms = [],&$ret = []) {
if (empty($items)) {
$ret[] = $perms;
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
$this->pc_permute($newitems, $newperms,$ret);
}
}
return $ret;
}
This will actually return an array with all possible permutations.
$options = ['startx','starty','startz','endx','endy','endz'];
$x = $this->pc_permute($options);
var_dump($x);
[0]=>
array(6) {
[0]=>
string(6) "startx"
[1]=>
string(6) "starty"
[2]=>
string(6) "startz"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[1]=>
array(6) {
[0]=>
string(6) "starty"
[1]=>
string(6) "startx"
[2]=>
string(6) "startz"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[2]=>
array(6) {
[0]=>
string(6) "startx"
[1]=>
string(6) "startz"
[2]=>
string(6) "starty"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[3]=>
array(6) {
[0]=>
string(6) "startz"
[1]=>
string(6) "startx"
[2]=>
string(6) "starty"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[4]=>
array(6) {
[0]=>
string(6) "starty"
[1]=>
string(6) "startz"
[2]=>
string(6) "startx"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[5]=>
array(6) {
[0]=>
string(6) "startz"
[1]=>
string(6) "starty"
[2]=>
string(6) "startx"
[3]=>
string(4) "endx"
[4]=>
string(4) "endy"
[5]=>
string(4) "endz"
}
[6]=> ................ a lot more
I found it a bit more usefull to get an array back instead of a string. Then it's up to the using application how to handle the resutls(to join them, or something else)
Simple version with recursion and no artificial extra arguments:
function permuteArray(array $input) {
$input = array_values($input);
// permutation of 1 value is the same value
if (count($input) === 1) {
return array($input);
}
// to permute multiple values, pick a value to put in the front and
// permute the rest; repeat this with all values of the original array
$result = [];
for ($i = 0; $i < count($input); $i++) {
$copy = $input;
$value = array_splice($copy, $i, 1);
foreach (permuteArray($copy) as $permutation) {
array_unshift($permutation, $value[0]);
$result[] = $permutation;
}
}
return $result;
}
This algorithm is nice and instructive how you would do it on paper, but otherwise very inefficient as it calculates same permutations multiple times. Not to say that it is very impractical for calculating permutations of larger arrays as the space and number of calculations grow exponentially.
Recursive function to get all permutations of an array.
Call getPermutations($arr) to get an array of arrays with all the permutations.
function getPermutations ($arr)
{
assert (!empty($arr));
if (count($arr)==1)
{
return [$arr];
}
$first=array_shift($arr);
$permutations=getPermutations($arr);
$result=[];
foreach ($permutations as $permutation)
{
$result=array_merge($result, addElementInAllPositions($permutation, $first));
}
return $result;
}
function addElementInAllPositions ($arr, $element)
{
$i=0;
$result=[];
while ($i<=count($arr))
{
$result[]=array_merge(array_slice($arr,0,$i), [$element], array_slice($arr, $i));
$i++;
}
return $result;
}
Here is another variant based on this article: https://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm
public static function get_array_orders( $arr ) {
$arr = array_values( $arr ); // Make sure array begins from 0.
$size = count( $arr ) - 1;
$order = range( 0, $size );
$i = 0;
$orders = [];
do {
foreach ( $order as $key ) {
$orders[ $i ][] = $arr[ $key ];
}
$i ++;
} while ( $order = self::get_next_array_order( $order, $size ) );
return $orders;
}
protected static function get_next_array_order( $order, $size ) {
// slide down the array looking for where we're smaller than the next guy
$i = $size - 1;
while ( isset( $order[ $i ] ) && $order[ $i ] >= $order[ $i + 1 ] ) {
$i --;
}
// if this doesn't occur, we've finished our permutations, the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
if ( $i == - 1 ) {
return false;
}
// slide down the array looking for a bigger number than what we found before
$j = $size;
while( $order[ $j ] <= $order[ $i ] ){
$j--;
}
// swap them
$tmp = $order[ $i ];
$order[ $i ] = $order[ $j ];
$order[ $j ] = $tmp;
// now reverse the elements in between by swapping the ends
for ( ++ $i, $j = $size; $i < $j; ++ $i, -- $j ) {
$tmp = $order[ $i ];
$order[ $i ] = $order[ $j ];
$order[ $j ] = $tmp;
}
return $order;
}
Example:
$langs = ['en', 'fr', 'ru'];
$orders = self::get_array_orders( $langs );
print_r($orders);
Outputs:
Array (
[0] => Array
(
[0] => en
[1] => fr
[2] => ru
)
[1] => Array
(
[0] => en
[1] => ru
[2] => fr
)
[2] => Array
(
[0] => fr
[1] => en
[2] => ru
)
[3] => Array
(
[0] => fr
[1] => ru
[2] => en
)
[4] => Array
(
[0] => ru
[1] => en
[2] => fr
)
[5] => Array
(
[0] => ru
[1] => fr
[2] => en
)
)

Combine multiple form array into 1 array

["trnx_date"]=>
array(2) {
[0]=>
string(10) "2017-01-10"
[1]=>
string(10) "2017-01-10"
}
["curr_from"]=>
array(2) {
[0]=>
string(3) "USD"
[1]=>
string(3) "PHP"
}
["curr_from_amt"]=>
array(2) {
[0]=>
string(8) "4,000.00"
[1]=>
string(8) "3,000.00"
}
["curr_to"]=>
array(2) {
[0]=>
string(3) "GBP"
[1]=>
string(3) "SAR"
}
["curr_to_amt"]=>
array(2) {
[0]=>
string(8) "3,000.00"
[1]=>
string(8) "2,000.00"
}
["amount"]=>
array(2) {
[0]=>
string(8) "7,000.00"
[1]=>
string(8) "5,000.00"
}
I have the above array which was being submitted. This input was in sets of multiple field which was generated by dynamic table row. How can I group this into 1 (one) array so that I could save in the database? Like this:
[cust_row] => array(
'tranx_date' => "2017-01-10",
'curr_from' => "USD",
'curr_from_amt' => "4,000.00",
'curr_to' => "GBP",
'curr_to_amt' => "3,000.00",
'amount' => "7,000.00"
),
[cust_row] => array(
'tranx_date' => "2017-01-10",
'curr_from' => "PHP",
'curr_from_amt' => "3,000.00",
'curr_to' => "SAR",
'curr_to_amt' => "2,000.00",
'amount' => "5,000.00"
),
All of the above we being populated like this:
$trnx_date = $this->input->post('trnx_date');
$curr_from = $this->input->post('curr_from');
$curr_from_amt = $this->input->post('curr_from_amt');
$curr_to = $this->input->post('curr_to');
$curr_to_amt = $this->input->post('curr_to_amt');
$amount = $this->input->post('amount');
Assuming all the sub-arrays have the same length, you can use a simple for loop that iterates over the index of one of them, and use that to access each of the sub-arrays at that index. Then combine all of them into the associative array for each customer.
$result = array();
$keys = array_keys($array);
$len = count($array[$keys[0]]); // Get the length of one of the sub-arrays
for ($i = 0; $i < $len; $i++) {
$new = array();
foreach ($keys as $k) {
$new[$k] = $array[$k][$i];
}
$result[] = $new;
}
$arr = array(
'trnx_date' => array('2017-01-10', '2017-01-10'),
'curr_from' => array('USD', 'PHP'),
'curr_from_amt' => array('4,000.00', '3,000.00'),
'curr_to' => array('GBP', 'SAR'),
'curr_to_amt' => array('3,000.00', '2,000.00'),
'amount' => array('7,000.00', '5,000.00')
);
$arr_out = array();
$arr_keys = array_keys($arr);
for($i = 0; $i < count($arr[$arr_keys[0]]); $i++) {
$new_arr = array();
foreach($arr_keys as $key => $value) {
$new_arr[$value] = $arr[$value][$i];
}
$arr_out[] = $new_arr;
}
var_dump($arr_out);
Hope it helps!
How about this?
// assume $arr is your original data array
$keys = array_keys($arr);
$result = array();
foreach($keys as $key) {
$vals = $arr[$key];
foreach($vals as $i =>$val) {
if (!is_array($result[$i]) {
$result[$i] = array();
}
$result[$i][$key] = $val;
}
}
var_dump($result);
EDIT: added array check for $result[$i]

Complex combination of words in PHP

I need a function to combinate words from an array. Yet, I have tried it with recursion but do not have get it yet. This is the example array I have:
[1]=> array(4) { [0]=> string(2) "ar" [1]=> string(2) "to" [2]=> string(4) "tron" [3]=> string(3) "var" }
[2]=> array(1) { [0]=> string(2) "to" }
[3]=> array(1) { [0]=> string(4) "tron" }
[4]=> array(4) { [0]=> string(2) "ar" [1]=> string(2) "to" [2]=> string(4) "tron" [3]=> string(3) "var" }
This means, that at position 1 one of the Strings "ar", "to", "tron" and "var" can take place. On position two only the String "to" can take place. And so on.
The length of the words should be the length of the array (in this case 4). All possible words should be returned as an array. For example here:
["artotronar", "artotronto", "artotrontron", "artotronvar", "tototronar", ...]
My idea was to write a recursive function, but I did not succeed in it. :-(
Best Regards
Richard
I think this is what you are looking for:
<?php
$syllables = array(
array('ar', 'to', 'tron', 'var'),
array('to'),
array('tron'),
array('ar', 'to', 'tron', 'var'),
);
$words = array();
$k = 0;
$max = 0;
for ($i = 1; $i < count($syllables); $i++) {
$max = max($max, count($syllables[$i]));
}
foreach ($syllables[0] as $syllable) {
for ($i = 0; $i < $max; $i++) {
$words[$k] = $syllable;
for ($j = 1; $j < count($syllables); $j++) {
$words[$k] .= $syllables[$j][min($i, count($syllables[$j]) - 1)];
}
$k++;
}
}
var_dump($words);
EDIT:
Here's a solution that will work for all inputs and generate every possible combination. The code assumes that $syllables will have at least one array.
<?php
$syllables = array(
array('ar', 'to', 'tron', 'var'),
array('to'),
array('tron'),
array('ar', 'to', 'tron', 'var'),
);
$p = 1;
foreach ($syllables as $syllableSet) {
$p = $p * count($syllableSet);
}
$words = array();
$n0 = count($syllables[0]);
for ($i = 0; $i < $p; $i++) {
$words[$i] = $syllables[0][$i % $n0];
}
for ($i = 1; $i < $n0; $i++) {
$pos = 0;
$ni = count($syllables[$i]);
for ($k = 0; $k < $p / $n0; $k++) {
for ($j = 0; $j < $n0; $j++) {
$words[$pos] .= $syllables[$i][$k % $ni];
$pos++;
}
}
}
var_dump($words);
I think this is the solution to your problem:
$pattern[] = array("ar", "to", "tron", "var");
$pattern[] = array("to");
$pattern[] = array("tron");
$pattern[] = array("ar", "to", "tron", "var");
$words = array();
foreach($pattern[0] as $p0) {
foreach($pattern[1] as $p1) {
foreach($pattern[2] as $p2) {
foreach($pattern[3] as $p3) {
$words[] = $p0.$p1.$p2.$p3;
}
}
}
}
echo "<pre>";
print_r($words);
echo "</pre>";
this will output all possible combinations of artotronvar, artotronar, etc...
but I didn't make a recursive function to call these...
and here are the output:
Array
(
[0] => artotronar
[1] => artotronto
[2] => artotrontron
[3] => artotronvar
[4] => tototronar
[5] => tototronto
[6] => tototrontron
[7] => tototronvar
[8] => trontotronar
[9] => trontotronto
[10] => trontotrontron
[11] => trontotronvar
[12] => vartotronar
[13] => vartotronto
[14] => vartotrontron
[15] => vartotronvar
)
Okay here's my code, I re-wrote the array at the top which obviously you won't have to do, but I left it in there so that you can see how it looks.
<?php
//The array that we are starting with
$parts = array(
array(
'ar',
'to',
'tron',
'var',
),
array(
'to',
),
array(
'tron',
),
array(
'ar',
'to',
'tron',
'var',
),
);
//Function to do our work
function makewords($parts){
//Set up an empty array to use as well as a word string for us to manipulate
$words = array();
$word = null;
//For each entry in this array
foreach($parts as $x){
//If this entry is also an array (it should be but this is just to make sure)
if(is_array($x)){
//Then for each of these entries...
foreach($x as $y){
//Create the word
$word .= $y;
}
//At this point our word is finished, so add it to the words array
$words[] = $word;
}
//Clear $word for the next one
$word = null;
}
//Now our array is done, so let's return it
return $words;
}
//Print it to check that it works
print_r(makewords($parts));
I hope this works for you.
To add it to the database, just add your database insert code where "return $words" is, however I'd do it this way and then enter it in to the database OUTSIDE of the function, otherwise the function will make an insert every time it's used; this way you can just use the function to create your array and then do what you please with it.

PHP sorting object array by certain criteria?

I have something like this:
$i = 0;
foreach($tracks['results'] as $track){
$trackName[$i] = $track['name'];
$trackPlaycount[$track['name']] = $track['playcount'];
$trackPercent[$track['name']] = $track['percent'];
$i++;
}
$this->trackName = $trackName;
$this->trackPlaycount = $trackPlaycount;
$this->trackPercent = $trackPercent;
how could I sort these objects by playcount? From what I have read so far I understand I should probably create a compare function and then make it work with usort(), right? But I'm not quite sure how to accomplish that...
thank you
edit: ok, so now I've got it like this:
public function firstmethod(){
// there are some more parameters here of course
// but they worked before, not important for the problem
$i = 0;
foreach($tracks['results'] as $track){
$trackName[$i] = $track['name'];
$trackPlaycount[$track['name']] = $track['playcount'];
$trackPercent[$track['name']] = $track['percent'];
// this part is new
$tracksArray[$i] = array(
'name' => $trackName[$i],
'playcount' => $trackPlaycount[$track['name']],
'percentage' => $trackPercent[$track['name']]
);
$i++;
}
usort($tracksArray, array($this, 'sortByCount'));
$i = 0;
// this is to put the new sorted array into the old variables?
foreach($tracksArray as $temp){
$trackName[$i] = $temp['name'];
$trackPlaycount[$trackName[$i]] = $temp['playcount'];
$trackPercent[$trackName[$i]] = $temp['percentage'];
$i++;
}
$this->trackName = $trackName;
$this->trackPlaycount = $trackPlaycount;
$this->trackPercent = $trackPercent;
}
public function sortByCount($a, $b){
if($a["playcount"] == $b["playcount"]) {
return 0;
}
return ($a["playcount"] < $b["playcount"]) ? -1 : 1;
}
this now works...
thank you everyone
usort example:
In the custom function you just access the array key you care about like this:
?php
$people = array(
array('id' => 1, 'name' => 'John', 'age' => 12),
array('id' => 2, 'name' => 'Mary', 'age' => 14),
array('id' => 3, 'name' => 'Aaaaaadam', 'age' => 15)
);
usort($people, "sortByName");
var_dump($people);
usort($people, "sortByAge");
var_dump($people);
function sortByName($a, $b) {
return strcmp($a["name"], $b["name"]);
}
function sortByAge($a, $b) { // or playcount or whatever
if($a["age"] == $b["age"]) {
return 0;
}
return ($a["age"] < $b["age"]) ? -1 : 1;
}
prints the sorted array (only pasted one so it's not getting to long, other output accordingly sorted by age)
array(3) {
[0]=>
array(3) {
["id"]=>
int(3)
["name"]=>
string(9) "Aaaaaadam"
["age"]=>
int(15)
}
[1]=>
array(3) {
["id"]=>
int(1)
["name"]=>
string(4) "John"
["age"]=>
int(12)
}
[2]=>
array(3) {
["id"]=>
int(2)
["name"]=>
string(4) "Mary"
["age"]=>
int(14)
}
}
You could also use an SplMaxHeap for this. Borrowing #edorian's $people array, you can do
class SortByAge extends SplMaxHeap
{
function compare($a, $b)
{
return $a['age'] - $b['age'];
}
}
$sort = new SortByAge;
foreach($people as $person) {
$sort->insert($person);
}
print_r(iterator_to_array($sort));
This should perform somewhat better than usort.

Categories