Merging array in recursive function using php? - php

After one week searching and converting many algorithm from other language into php to make an array that contain "combination k from n". I'm stuck.
please help me.
This is my code (using php):
function comb($item,$arr,$out, $start, $n, $k, $maxk) {
if ($k > $maxk) {
foreach($arr as $ar){
echo "$ar";
echo "<br/>";
}
return;
}
for ($i=$start; $i<=$n; $i++) {
$arr[$k] = $item[$i-1];
comb($isi, $arr, $out, $i+1, $n, $k+1, $maxk);
}
}
$team = array("A","B","C","D");
$ar = array();
$o = array();
comb($team,$ar,$o,1,4,1,2);
Recursive algorithm above is really confuse me. The code above was successful to form the combination but I cannot merge them into one array because of its recursive characteristics. I just want to make an array that contain the result of combination of 2 from 4 items. Like this (see below)
Array (
[0] => Array (
[1] => A
[2] => B
)
[1] => Array (
[1] => A
[2] => C
)
[2] => Array (
[1] => A
[2] => D
)
[3] => Array (
[1] => B
[2] => C
)
[4] => Array (
[1] => B
[2] => D
)
[5] => Array (
[1] => C
[2] => D
)
)
I know I still far from the answer. But please guide me, to reach that answer. Perhaps you know the other technique, it doesn't matter. If your code works, I will use it. No matter what the technique you've used. Any ideas would be gratefully appreciated,Thank you..!

An (I think) simpler recursive implementation is:
<?php
/* Given the array $A, returns the array of $k-subsets
of $A in lexicographical order. */
function k_lex_subset($A,$k) {
if (($k <= 0) or (count($A) < $k)) { return array(); }
else if ($k <= 1) { return array_chunk($A,1); }
else {
$v = array_shift($A);
$AwA = k_lex_subset($A,$k-1);
foreach($AwA as &$vp) {
array_unshift($vp,$v);
}
$AwoA = k_lex_subset($A,$k);
$resultArrs = array_merge($AwA, $AwoA);
return($resultArrs);
}
}
$team = array("A","B","C","D");
print_r(k_lex_subset($team,2));
?>
which returns
Array
(
[0] => Array
(
[0] => A
[1] => B
)
[1] => Array
(
[0] => A
[1] => C
)
[2] => Array
(
[0] => A
[1] => D
)
[3] => Array
(
[0] => B
[1] => C
)
[4] => Array
(
[0] => B
[1] => D
)
[5] => Array
(
[0] => C
[1] => D
)
)
and will work for any size array, and any $k.
The term you are looking for is (lexicographical) k-subset enumeration where $k is 2 in this specific case.
Explanation
The idea is very simple. Assume we have (for example) a set {A,B,C,D}. We want to start with all sets with A in, and so we consider subsets of size 1-less coming from {B,C,D} and append A to them yielding
{{A,B}, {A,C}, {A,D}}
and then we consider all subsets of size 2 without A in
{{B,C}, {B,D}, {C,D}}
and then we just merge the two. It is hopefully easy to see how, in general, this yields a nice recursive strategy for constructing the k-subsets of a set (instead of just k=2).
Reference
A fantastic reference on this sort of thing is Vol 4 Fasicle 3 of Knuth's The Art of Computing Programming.

This should do the trick to reach the array you've described above:
<?php
$array = array("A","B","C","D");
function transformArray( $array ) {
$returnArray = array();
for( $i=0; $i < count($array); $i++ ) {
for( $j=$i+1; $j < count($array); $j++ ) {
$returnArray[] = array( $array[$i], $array[$j] );
}
}
return $returnArray;
}
print_r(transformArray($array));
?>

Not exactly sure on the necessity of start, n, and k, but this should get you the expected output. If you provide some more details on why those counters would be necessary, we can get you a more thorough answer.
function comb($itemArray, $start, $n, $k, $maxk) {
//if ($k > $maxk) return;
$outputArray = array();
foreach($itemArray AS $index => $firstChar) {
for($i = $index+1; $i<count($itemArray); $i++) {
$secondChar = $itemArray[$i];
$outputArray[] = array($firstChar, $secondChar);
}
}
return $outputArray;
}
$teamArray = array("A","B","C","D");
$resultArray = comb($teamArray,1,4,1,2);
ppr($resultArray);
function ppr($variable) {
echo '<pre>';
print_r($variable);
echo '</pre>';
}

function comb($a, $len){
if ($len > count($a))return array();
$out = array();
if ($len==1) {
foreach ($a as $v) $out[] = array($v);
return $out;
}
$len--;
while (count($a) > $len) {
$b = array_shift($a);
$c = comb($a, $len);
foreach ($c as $v){
array_unshift($v, $b);
$out[] = $v;
}
}
return $out;
}
$test = array('a','b','c','d');
$a = comb($test,2);
print_r($a);
would give you:
Array(
[0] => Array
(
[0] => a
[1] => b
)
[1] => Array
(
[0] => a
[1] => c
)
[2] => Array
(
[0] => a
[1] => d
)
[3] => Array
(
[0] => b
[1] => c
)
[4] => Array
(
[0] => b
[1] => d
)
[5] => Array
(
[0] => c
[1] => d
)
)

Why are you doing
echo "ar"
instead of
echo $ar
Also are you looking for permutation or combination? Here is a site with very nice algorithms for both. The implementation is in java but it's very clear. so converting to php won't be difficult: http://geekviewpoint.com/Numbers_functions_in_java/

If you want a pure clean recursive way use this:
function comb($item, $n) {
return comb_rec($item, array(), $n);
}
function comb_rec($items, $c, $n) {
if (count($c) == $n) {
return array($c);
}else{
if (count($items) == 0) {
return $items;
}else{
$list = $items;
$head = array_shift($list);
$tail = $list;
$current = $c;
array_push($current,$head);
return array_merge(comb_rec($tail, $current, $n),comb_rec($tail, $c, $n));
}
}
}
$team = array("A","B","C","D");
$all = comb($team,2);
print_r($all);

Related

convert string to multidimensional array

I have this array
dev3->content->->mktg->->->pls1->->->pls2->->->config->->splash
I want to convert this string to multidimensional array. like this
Array
(
[0] => dev3
Array (
[0] => ->content
Array (
[0] => ->->mktg
Array(
[0] => ->->->pls1
[1] => ->->->pls2
[2] => ->->->config
)
[1] => ->->splash
)
)
)
Can anyone do this
it does not work if level will be increaed more then +1 on any step
$str = 'dev3->content->->mktg->->->pls1->->->pls2->->->config->->splash';
$in = preg_split('/(?<!>)(?=->)/', $str);
Above we make such array from the input string
Array
(
[0] => dev3
[1] => ->content
[2] => ->->mktg
[3] => ->->->pls1
[4] => ->->->pls2
[5] => ->->->config
[6] => ->->splash
)
continue working
$result = [];
$p = &$result;
$level = 0;
foreach($in as $i) {
// Count next level
$c = substr_count($i, '->');
// if level is not changed
if($c == $level) { $p[] = $i; continue; }
// level increased
if ($c == $level + 1) {
$level++;
$p[] = [$i];
$p = &$p[count($p)-1];
continue;
}
// any level less then achived before
if ($c < $level) {
$p = &$result;
$level = $c;
while($c--)
$p = &$p[count($p)-1];
$p[] = $i;
continue;
}
die("I can't process this input string");
}
print_r($result);
working demo

Need some help making a php search tree

Im making a tree to store words and an associated number array in php. I need it to look something like this:
Words: apple, ant
[a] => Array
(
[p] => Array
(
[p] => Array
(
[l] => Array
(
[e] => Array
(
[0] => Array
(
[0] => 0
[1] => 0
[2] => 1
[3] => 2
[4] => 3
[5] => 4
)
)
)
)
)
[n] => Array
(
[t] => Array
(
[0] => Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 0
[4] => 0
[5] => 4
)
)
)
)
Of course apple and ant need to share the same [a] index. Im close, but I cant figure out how to properly keep track of the tree index so 'apple' gets into the tree fine but 'ant' is inserted as 'nt'. Heres my code at the moment:
private function insertWordsIntoTree()
{
foreach ($this->words as $word)
{
$characters = preg_replace('/[0-9]+/', '', $words);
$points = $this->getPoints($word);
$this->tree = $this->buildTree($characters, $points, $this->tree);
}
print_r($this->tree);
}
private function buildTree($characters, array $points, array $tree)
{
for ($i = 0; $i < strlen($characters); $i++)
{
$character = $characters[$i];
$remaining_characters = substr($characters, $i + 1);
if (strlen($characters) === 1)
{
$child = [];
$child[$character] = [$points];
return $child;
}
elseif (!isset($tree[$character]))
{
$tree[$character] = $this->buildTree($remaining_characters, $points, []);;
break;
}
else
{
$this->buildTree($remaining_characters, $points, $tree[$character]);
}
}
return $tree;
}
Im pretty sure the problem is at the else statement...I dont think Im keeping track of the current tree index properly. Any help would be much appreciated.
Here's a simple approach that passes the recursion off to php:
$tree = array();
foreach($words as $word) {
$characters = array_reverse(str_split($word));
$temp = array();
foreach($characters as $index => $character) {
if($index == 0) {
$temp[] = getPoints($word);
}
$temp = array(
$character => $temp
);
}
$tree = array_merge_recursive($tree, $temp);
}

PHP Sort Mega-Array by Value

I am looking for some advices how could I sort this kind of Array by 'variant_name' key.
Because Array is really huge I minified it to the looking result state.
...
$filter[2413][1][81][sub_id] = 1;
$filter[2413][1][81][variant_id] = 81;
$filter[2413][1][81][variant_name] = 'Banana';
$filter[2413][2][87][sub_id] = 2;
$filter[2413][2][87][variant_id] = 87;
$filter[2413][2][87][variant_name] = 'Apple';
$filter[2413][3][32][sub_id] = 3;
$filter[2413][3][32][variant_id] = 32;
$filter[2413][3][32][variant_name] = 'Carrot';
...
Keys $filter[x][x][x] are not sequential.
I have tried the sort function I used before but it doesn't work with this kind of Array:
function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) {
$sort_col = array();
foreach ($arr as $key=> $row) {
$sort_col[$key] = $row[$col];
}
array_multisort($sort_col, $dir, $arr);
}
array_sort_by_column($filter[][][], 'variant_name');
My target is modify array by sorting 'variant_name' to 'Apple', 'Banana', 'Carrot' accordingly keeping the array structure.
It's a working code tested from given examples.
Note that my codes still can be optimized, etc. Just take it as my advice.
TL;DR = Use usort().
function mySort($a,$b)
{
$av = "";
$bv = "";
foreach($a as $ak)
$av = $ak['variant_name'];
foreach($b as $bk)
$bv = $bk['variant_name'];
if($av[0] < $bv[0])
return false;
else return true;
}
How to use it? You have to specify which first level array to sort.
usort($filter['2413'],"mySort");
Then the result I got is:
Array
(
[2413] => Array
(
[0] => Array
(
[87] => Array
(
[sub_id] => 2
[variant_id] => 87
[variant_name] => Apple
)
)
[1] => Array
(
[81] => Array
(
[sub_id] => 1
[variant_id] => 81
[variant_name] => Banana
)
)
[2] => Array
(
[32] => Array
(
[sub_id] => 3
[variant_id] => 32
[variant_name] => Carrot
)
)
)
)

Small sorting algorithm in php

It should quite simple algorithm, but I just can't get around it.
I have some arrays in alphabetical order
[0] => Array
(
[0] => a
[1] => b
[2] => c
)
and for example
[0] => Array
(
[0] => a
[1] => b
[2] => c
[3] => d
)
and I need to sort them into rows. For example:
I should receive a table with 3 columns and as many rows as it may get and it should be in alphabetical order.
Here is an example:
First array should be converted into
[0] => Array
(
[0] => Array
(
[0] => a
[1] => b
[2] => c
)
)
But second one should be as
[1] => Array
(
[0] => Array
(
[0] => a
[1] => c
[2] => d
)
[1] => Array
(
[0] => b
)
)
I'm writing it in php, so if anyone can help I would be really appreciated.
UPD:
Code example:
function sortAsOrdered( array $categories )
{
foreach ( $categories as $groupId => $group )
{
$regroupMenuItems = array();
$limit = count( $group );
$rows = ceil( $limit / 3 );
for ( $i = 0; $i < $rows; ++$i )
{
$jumper = 0;
for ( $j = 0; $j < 3; $j++ )
{
if ( 0 == $jumper )
{
$jumper = $i;
}
if ( isset( $group[ $jumper ] ) )
{
$regroupMenuItems[ $i ][ $j ] = $group[ $jumper ];
}
$jumper = $jumper + $rows;
}
}
$categories[ $groupId ] = $regroupMenuItems;
}
return $categories;
}
Guys I solved this one. Here you could see my algorithm http://pastebin.com/xe2yjhYW.
But don't be sad your help will not go in vain. I probably will place bounty just for those who helped with this dificult algorithm for me.
Guys thanks one more time. Your thoughts inspired me to think differently.
array_chunk() wold have been the solution but as you want it to be specially sorted, that wouldn't help you much.
So here is my five cents:
function array_chunk_vertical($input, $size_max) {
$chunks = array();
$chunk_count = ceil(count($input) / $size_max);
$chunk_index = 0;
foreach ($input as $key => $value) {
$chunks[$chunk_index][$key] = $value;
if (++$chunk_index == $chunk_count) {
$chunk_index = 0;
}
}
return $chunks;
}
$array = array('a', 'b', 'c', 'd', 'e', 'f');
var_dump(array_chunk_vertical($array, 2));
Which will give you:
array
0 =>
array
0 => string 'a' (length=1)
3 => string 'd' (length=1)
1 =>
array
1 => string 'b' (length=1)
4 => string 'e' (length=1)
2 =>
array
2 => string 'c' (length=1)
5 => string 'f' (length=1)
The downside of this function is that you can only tell the max number of elements in a chunk, and then it equally divides the array to chunks. So for [4] and max_size 3 you will get [2,2] unlike the expected [3,1].
<?php
$five_el = array('a', 'b', 'c', 'd', 'e');
$two_el = array('a', 'b');
$three_el = array('a', 'b', 'c');
$six_el = array('a', 'b', 'c', 'd', 'e', 'f');
function multid($sorted_array) {
$mulidarray = array();
$row = 0;
$column = 0;
foreach ($sorted_array as $value) {
if ($column == 3) {
$row++;
}
$column++;
if (!isset($mulidarray[$row])) {
$mulidarray[$row] = array();
}
$multidarray[$row][] = $value;
}
return $multidarray;
}
var_dump(multid($five_el));
var_dump(multid($two_el));
var_dump(multid($three_el));
var_dump(multid($six_el));
array_chunk is a natural first approach to the problem, but it won't do exactly what you need to. If the solution is provided that way, you need to either restructure the resulting array or restructure the input before processing it, as below:
$input = range('a', 'k'); // arbitrary
$columns = 3; // configure this
$rows = ceil(count($input) / $columns);
// fugly, but this way it works without declaring a function
// and also in PHP < 5.3 (on 5.3 you'd use a lambda instead)
$order = create_function('$i',
'$row = (int)($i / '.$rows.');'.
'$col = $i % '.$rows.';'.
'return $col * ('.$columns.' + 1) + $row;');
// $order is designed to get the index of an item in the original array,
// and produce the index that item would have if the items appeared in
// column-major order instead of row-major as they appear now
$array = array_map($order, array_keys($input));
// replace the old keys with the new ones
$array = array_combine($array, $input);
// sort based on the new keys; this will effectively transpose the matrix,
// if it were already structured as a matrix instead of a single-dimensional array
ksort($array);
// done!
$array = array_chunk($array, $columns);
print_r($array);
See it in action.
Let's see if this is nearer the mark
function splitVerticalArrayIntoColumns($aInput, $iNumberOfColumns) {
//output array
$aOutput = array();
//the total length of the input array
$iInputLength = count($aInput);
//the number of rows will be ceil($iInputLength / $iNumberOfColumns)
$iNumRows = ceil($iInputLength / $iNumberOfColumns);
for($iInputIndex = 0; $iInputIndex < $iInputLength; $iInputIndex++) {
$iCurrentRow = $iInputIndex % $iNumRows;
$aOutput[$iCurrentRow][] = $aInput[$iInputIndex];
}
//return
return $aOutput;
}
Which - when run thus:
$aList = array("a", "e", "d", "b", "c");
echo 'array("a", "e", "d", "b", "c")' . "\n\n";
print_r(splitVerticalArrayIntoColumns($aList, 3));
Gives:
array("a", "e", "d", "b", "c")
Array
(
[0] => Array
(
[0] => a
[1] => d
[2] => c
)
[1] => Array
(
[0] => e
[1] => b
)
)
That's not sorting each row yet but is that the kind of thing you're after?
begin facepalm edit
... or of course, array_chunk($aList, 3) after you've sorted it O_o
http://uk3.php.net/manual/en/function.array-chunk.php
I'll leave everything below for reference or whatever - I'd completely forgotten about array_chunk()
end facepalm edit
I'd use a modulo in a loop where you're counting the array index (after sorting the array) - for instance if you're trying to split an array into 3 "columns" you could try something like:
if($iIndex % 3 == 0) {
//... create a new array
}
else {
//... add to an existing array
}
EDIT code example:
$aList = array("a", "e", "d", "b", "c");
sort($aList);
$iDesiredNumberOfColumns = 3;
$iListLength = count($aList);
$aListInColumns = array();
$iRowNumber = 0;
for($iIndex = 0; $iIndex < $iListLength; $iIndex++) {
$iColumnNumber = $iIndex % 3;
if($iIndex != 0 && $iColumnNumber == 0) {
$iRowNumber++;
}
$aListInColumns[$iRowNumber][$iColumnNumber] = $aList[$iIndex];
}
Just ran it on my local server (and corrected the typo), and it outputs as:
Array
(
[0] => Array
(
[0] => a
[1] => b
[2] => c
)
[1] => Array
(
[0] => d
[1] => e
)
)
There's probably a tidier way of doing it (that's a little procedural) but it should do the job.
How about:
$arrs = array(
array('a','b','c'),
array('a','b','c','d'),
array('a','b','c','d','e'),
array('a','b','c','d','e','f'),
array('a','b','c','d','e','f','g')
);
$nbcols = 3;
foreach ($arrs as $arr) {
$arr_size = count($arr);
$nblines = ceil($arr_size/$nbcols);
$res = array();
$l = 0;
foreach ($arr as $el) {
if ($l == $arr_size - 1 && count($res[0]) < $nbcols) $l=0;
$res[$l%$nblines][] = $el;
$l++;
}
print_r($res);
}
output:
Array
(
[0] => Array
(
[0] => a
[1] => b
[2] => c
)
)
Array
(
[0] => Array
(
[0] => a
[1] => c
[2] => d
)
[1] => Array
(
[0] => b
)
)
Array
(
[0] => Array
(
[0] => a
[1] => c
[2] => e
)
[1] => Array
(
[0] => b
[1] => d
)
)
Array
(
[0] => Array
(
[0] => a
[1] => c
[2] => e
)
[1] => Array
(
[0] => b
[1] => d
[2] => f
)
)
Array
(
[0] => Array
(
[0] => a
[1] => d
[2] => g
)
[1] => Array
(
[0] => b
[1] => e
)
[2] => Array
(
[0] => c
[1] => f
)
)
In order to do this, you need to do two operations:
First, split the array into 3 groups, as evenly as possible.
function array_grouped($arr, $group_count)
{
if (!count($arr)) return array();
$result = array();
for ($i = $group_count; $i > 0; --$i)
{
# break off the next ceil(remaining count / remaining columns) elements
# (avoiding FP math, cause that way lies madness)
$result[] = array_splice($arr, 0, ((count($arr)-1) / $i) + 1);
}
return $result;
}
Then, "transpose" the array, so that rows and columns switch places.
function array_transposed($arr)
{
$result = array();
foreach ($arr as $x => $subarr)
{
foreach ($subarr as $y => $val)
{
if (!isset($result[$y])) $result[$y] = array();
$result[$y][$x] = $val;
}
}
return $result;
}
array_transposed(array_grouped($arr, 3)) gives you entries in the order you want them.
YAYAYAY!! I've got it. You could turn this into a function if you'll be doing it regularly.
# Here we setup our array and the number of columns we want.
$myArray = range('a','d');
$numCols = 3;
# Here we break ourselves up into columns
for ($i = 0; $i < $numCols; $i++) {
$numRows = ceil(count($myArray) / ($numCols - $i));
$columns[$i] = array_slice($myArray,0,$numRows);
$myArray = array_slice($myArray,$numRows);
}
# Here we transpose our array to be in rows instead of columns.
for ($i = 0; $i < $numCols; $i++) {
for ($j = 0; $j < count($columns[$i]); $j++) {
$rows[$j][$i] = $columns[$i][$j];
}
}
# Our rows are now in $rows
var_dump($rows);
The output from this is:
array(2) {
[0]=>
array(3) {
[0]=>
string(1) "a"
[1]=>
string(1) "c"
[2]=>
string(1) "d"
}
[1]=>
array(1) {
[0]=>
string(1) "b"
}
}
If to say it shortly, then here is a method for that algorithm.
/**
* #param array $toTransform
* #param int $columnsMax
* #return array
*/
private function transformation( array $toTransform, $columnsMax = 3 )
{
// First divide array as you need
$listlen = count( $toTransform );
$partlen = floor( $listlen / $columnsMax );
$partrem = $listlen % $columnsMax;
$partition = array();
$mark = 0;
for ( $px = 0; $px < $columnsMax; $px++ )
{
$incr = ( $px < $partrem ) ? $partlen + 1 : $partlen;
$partition[ $px ] = array_slice( $toTransform, $mark, $incr );
$mark += $incr;
}
// Secondly fill empty slots for easy template use
$result = array();
for ( $i = 0; $i < count( $partition[0] ); $i++ )
{
$tmp = array();
foreach ( $partition as $column )
{
if ( isset( $column[ $i ] ) )
{
$tmp[] = $column[ $i ];
}
else
{
$tmp[] = '';
}
}
$result[] = $tmp;
}
return $result;
}
Also I included PHPUnit test for that. You can find it at, that link.

How to find every possible combination of an arbitrary number of arrays in PHP

I have an arbitrary number of nested arrays in php. For example:
Array
(
[0] => Array
(
[0] => 36
[0] => 2
[0] => 9
)
[1] => Array
(
[0] => 95
[1] => 21
[2] => 102
[3] => 38
)
[2] => Array
(
[0] => 3
[1] => 5
)
)
I want to find the most efficient way to combine all possible combinations of each of these nested arrays. I'd like to end up with something that looks like this...
Array
(
[0] => "36,95,3"
[1] => "36,95,5"
[2] => "36,21,3"
[3] => "36,21,5"
etc...
)
The order the results are combined in is not important. That is to say, there is no difference between "3,95,36", "36,95,3", and "95,36,3". I would like to omit these redundant combinations.
Any suggestions on how to go about this would be much appreciated.
Thanks in advance,
<?php
$a = array("01", "02");
$b = array("white", "green");
$c = array("one", "two", "three");
$aG = array($a, $b, $c);
$codes = array();
$pos = 0;
generateCodes($aG);
function generateCodes($arr) {
global $codes, $pos;
if(count($arr)) {
for($i=0; $i<count($arr[0]); $i++) {
$tmp = $arr;
$codes[$pos] = $arr[0][$i];
$tarr = array_shift($tmp);
$pos++;
generateCodes($tmp);
}
} else {
echo join(", ", $codes)."<br/>";
}
$pos--;
}
?>
General permutation solution for any number of groups (in Groovy to keep it simple).
list = [["A", "B", "W"], ["C", "D"], ["X", "Y"]]
r = []
void p(List<List<String>> l, int n) {
for(t in l[n]) {
r[n] = t
if (n < l.size() - 1) {
p(l, n + 1)
} else {
println(r)
}
}
}
p(list, 0);

Categories