Small sorting algorithm in php - 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.

Related

Merging arrays with keys that share the same number of items

I have a basic function that takes two arrays and merges them based on key. It is meant to work with arrays that have different keys but ultimately the same number of items. The function works well. However, it only inputs two arrays at a time to merge.
How can I modify so it takes n number of arrays to merge?
PHP
protected function arrayMergeKeys( $a, $b )
{
$retArr = array();
// I used min(countA, countB) so there will be no errors on
// unbalanced array item counts.
for ( $i = 0; $i < min( count( $a ), count( $b ) ); $i++ ) {
$retArr[ $i ] = array_merge( $a[ $i ], $b[ $i ] );
} // for end
return $retArr;
}
Desired result is to call the function with three arrays: $merged_arrays = arrayMergeKeys($a, $b, $c);
Input
//$a
Array
(
[a] => 'new value'
[b] => 2
[c] => 3
)
//$b
Array
(
[1] => 'blah'
[2] => 'dud'
[3] => 697
)
//$c
Array
(
[pet] => 'dog'
[breed] => 'german shepher'
[age] => 100
)
Output
Array
{
[a] => 'new value'
[1] => 'blah'
[pet] => 'dog'
}
Array
{
[b] => 2
[2] => 'dud'
[breed] => 'german shepher'
}
Array
{
[c] => 3
[3] => 697
[age] => 100
}
Leaving your original function untouched you could do it like this:
function arrayMulitMergeKeys() {
$arrayArgs = func_get_args();
$c = count($arrayArgs);
$result = arrayArgs[0];
for($i = 1; $i < $c; $i++) {
$result = arrayMergeKeys($result, $arrayArgs[$i]);
}
return $result;
}
This can be optimized further please re-check it once again
function arrayMergeKeys()
{
$retArr = array();
$arrayArgs = func_get_args();
//print_r($arrayArgs);
$minCount = count($arrayArgs[0]);
foreach($arrayArgs as $array){
if($minCount > count($array)){
$minCount = count($array);
}
}
// I used min(countA, countB) so there will be no errors on
// unbalanced array item counts.
for ( $i = 0; $i < $minCount; $i++ ) {
foreach($arrayArgs as $array){
$iCount = count($array);
for($j=0; $j<=$iCount; $j++)
{
if($i==$j){
$arrayKeys = array_keys($array);
if(isset($arrayKeys[$i])){
$retArr[ $i ][$arrayKeys[$i]] = $array[$arrayKeys[$i]];
break;
}
}
}
}
} // for end
return $retArr;
}
$a = Array
(
'a' => 'new value',
'b' => 2,
'c' => 3
);
$b = array
(
'1' => 'blah',
'2' => 'dud',
'3' => 697
);
$c = array
(
'pet' => 'dog',
'breed' => 'german shepher',
'age' => 100
);
print_r(arrayMergeKeys($a, $b, $c));
Here's some pseudo code to point you in the right direction.
function mergeArrays(a, b, c)
arrays = []
shortestLength = min(a.len, b.len, c.len)
for i in [0 .. shortestLength - 1]
arrays[i] = [ a[i], b[i], c[i] ];
return arrays
If you're doing this as an exercise, I would suggest implementing the following also:
mergeArrays(arr) where arr is an array of arrays that need to be merged.
Haven't tested, but this should work
protected function arrayMergeKeys(...$arrs) {
$retArr = array();
// I used min(countA, countB) so there will be no errors on
// unbalanced array item counts.
$countArr = array();
foreach ($arrs as $arr) {
$countArr[] = count($arr);
}
$min = min($countArr);
for ( $i = 0; $i < $min; $i++ ) {
$mergeArr = array();
foreach ($arrs as $arr) {
$mergeArr[] = $arr[$i];
}
$retArr[ $i ] = array_merge( $mergeArr );
} // for end
return $retArr;
}
You can simply 'add' the arrays:
$a = array
(
'a' => 'new value',
'b' => '2',
'c' => '3'
);
//$b
$b = array
(
'1' => 'blah',
'2' => 'dud',
'3' => '697'
);
//$c
$c = array
(
'pet' => 'dog',
'breed' => 'german shepher',
'age' => 100
);
$result= $a+$b+$c;
print_r($result);
output
Array ( [a] => new value [b] => 2 [c] => 3 [1] => blah [2] => dud [3] => 697 [pet] => dog [breed] => german shepher [age] => 100 )

PHP Function for Comparing Elements in Different Arrays

I have two arrays like so (however there can be more or less than 2 (any amount)):
[0] => Array
(
[assessedUsers] => Array
(
[0] => Array
(
[scores] => Array
(
[0] => 10
[1] => 10
[2] => 10
[3] => 10
)
)
[1] => Array
(
[scores] => Array
(
[0] => 9
[1] => 10
[2] => 0
[3] => 9
)
)
)
)
Where the length of the scores array is always the same in both arrays.
I would like to take each element from each array, one by one, and average them, then append them into a new array.
For example, the output of my desired function would look like this:
[1] => Array
(
[scores] => Array
(
[0] => 9.5
[1] => 10
[2] => 5
[3] => 9.5
)
)
Is there a function that can do this, or do I need a couple nested for() loops? If I need to use forl loops how would I go about doing it? I'm a little confused on the logic behind it.
Currently what I have is:
for ($i = 0; $i < sizeof($data["assessedUsers"]); $i++) {
for ($j = 0; $j < sizeof($data["assessedUsers"][$i]["scores"]); $j++) {
}
}
and I'm a little confused as to what to where to go next. Thanks in advance!
$mean = array_map( function($a, $b) { return ($a + $b) / 2; },
$data['assessedUsers'][0]['scores'],
$data['assessedUsers'][1]['scores']
);
var_dump($mean);
And append $mean anywhere you want. Or do you have more than 2 arrays? You did not state it in your question.
ps: for any number of subarrays
$arr = array(
array('scores' => array(10,10,10,10)),
array('scores' => array(9,10,0,9)),
array('scores' => array(1,2,3,4))
);
// remove arrays from the key
$tmp = call_user_func_array( function() { return func_get_args(); },
array_map( function($a) { return $a['scores']; }, $arr)
);
// add arrays by each element
$mean = array_map( function($val, $ind) use($tmp) {
$sum = 0;
foreach($tmp as $i => $t)
$sum += $t[$ind];
return $sum / ($i + 1);
}, $tmp[0], array_keys($tmp[0]));
var_dump($mean);
Probably two loops:
$newarray();
foreach($main_array as $user) {
foreach($user['assessedUser'][0]['scores'] as $score_key => $user0_value) {
$user1_value = $user['assessedUser'][1]['scores'][$score_key];
$average = ($user1_value + $user0_value) / 2;
... stuff into new array
}
}
I have solution for you, hope this help :)
$scores = array();
for ($i = 0; $i < sizeof($data["assessedUsers"]); $i++) {
for ($j = 0; $j < sizeof($data["assessedUsers"][$i]["scores"]); $j++) {
if(isset($scores[$j])){
$scores[$j] = ($scores[$j] + $data["assessedUsers"][$i]["scores"][$j]) / ($i +1);
}else{
$scores[] = $data["assessedUsers"][$i]["scores"][$j];
}
}
}
$scores[] = $scores;
view Example :)
http://codepad.org/upPjMEym

combine arrays and concat value?

Little complex to explain , so here is simple concrete exemple :
array 1 :
Array
(
[4] => bim
[5] => pow
[6] => foo
)
array 2 :
Array
(
[n] => Array
(
[0] => 1
)
[m] => Array
(
[0] => 1
[1] => 2
)
[l] => Array
(
[0] => 1
[1] => 4
[2] => 64
)
And i need to output an array 3 ,
array expected :
Array
(
[bim] => n-1
[pow] => Array
(
[0] => m-1
[1] => m-2
)
[foo] => Array
(
[0] => l-1
[1] => l-4
[2] => l-64
)
Final echoing OUTPUT expected:
bim n-1 , pow m-1 m-2 ,foo l-1 l-4 l-64 ,
I tried this but seems pity:
foreach($array2 as $k1 =>$v1){
foreach($array2[$k1] as $k => $v){
$k[] = $k1.'_'.$v);
}
foreach($array1 as $res =>$val){
$val = $array2;
}
Thanks for helps,
Jess
CHALLENGE ACCEPTED
<?php
$a = array(
4 => 'bim',
5 => 'pow',
6 => 'foo',
);
$b = array(
'n' => array(1),
'm' => array(1, 2),
'l' => array(1, 4, 64),
);
$len = count($a);
$result = array();
$aVals = array_values($a);
$bKeys = array_keys($b);
$bVals = array_values($b);
for ($i = 0; $i < $len; $i++) {
$combined = array();
$key = $aVals[$i];
$prefix = $bKeys[$i];
$items = $bVals[$i];
foreach ($items as $item) {
$combined[] = sprintf('%s-%d', $prefix, $item);
};
if (count($combined) === 1) {
$combined = $combined[0];
}
$result[$key] = $combined;
}
var_dump($result);
?>
Your code may be very easy. For example, assuming arrays:
$one = Array
(
4 => 'bim',
5 => 'pow',
6 => 'foo'
);
$two = Array
(
'n' => Array
(
0 => 1
),
'm' => Array
(
0 => 1,
1 => 2
),
'l' => Array
(
0 => 1,
1 => 4,
2 => 64
)
);
You may get your result with:
$result = [];
while((list($oneKey, $oneValue) = each($one)) &&
(list($twoKey, $twoValue) = each($two)))
{
$result[$oneValue] = array_map(function($item) use ($twoKey)
{
return $twoKey.'-'.$item;
}, $twoValue);
};
-check this demo Note, that code above will not make single-element array as single element. If that is needed, just add:
$result = array_map(function($item)
{
return count($item)>1?$item:array_shift($item);
}, $result);
Version of this solution for PHP4>=4.3, PHP5>=5.0 you can find here
Update: if you need only string, then use this (cross-version):
$result = array();
while((list($oneKey, $oneValue) = each($one)) &&
(list($twoKey, $twoValue) = each($two)))
{
$temp = array();
foreach($twoValue as $item)
{
$temp[] = $twoKey.'-'.$item;
}
$result[] = $oneValue.' '.join(' ', $temp);
};
$result = join(' ', $result);
As a solution to your problem please try executing following code snippet
<?php
$a=array(4=>'bim',5=>'pow',6=>'foo');
$b=array('n'=>array(1),'m'=>array(1,2),'l'=>array(1,4,64));
$keys=array_values($a);
$values=array();
foreach($b as $key=>$value)
{
if(is_array($value) && !empty($value))
{
foreach($value as $k=>$val)
{
if($key=='n')
{
$values[$key]=$key.'-'.$val;
}
else
{
$values[$key][]=$key.'-'.$val;
}
}
}
}
$result=array_combine($keys,$values);
echo '<pre>';
print_r($result);
?>
The logic behind should be clear by reading the code comments.
Here's a demo # PHPFiddle.
//omitted array declarations
$output = array();
//variables to shorten things in the loop
$val1 = array_values($array1);
$keys2 = array_keys($array2);
$vals2 = array_values($array2);
//iterating over each element of the first array
for($i = 0; $i < count($array1); $i++) {
//if the second array has multiple values at the same index
//as the first array things will be handled differently
if(count($vals2[$i]) > 1) {
$tempArr = array();
//iterating over each element of the second array
//at the specified index
foreach($vals2[$i] as $val) {
//we push each element into the temporary array
//(in the form of "keyOfArray2-value"
array_push($tempArr, $keys2[$i] . "-" . $val);
}
//finally assign it to our output array
$output[$val1[$i]] = $tempArr;
} else {
//when there is only one sub-element in array2
//we can assign the output directly, as you don't want an array in this case
$output[$val1[$i]] = $keys2[$i] . "-" . $vals2[$i][0];
}
}
var_dump($output);
Output:
Array (
["bim"]=> "n-1"
["pow"]=> Array (
[0]=> "m-1"
[1]=> "m-2"
)
["foo"]=> Array (
[0]=> "l-1"
[1]=> "l-4"
[2]=> "l-64"
)
)
Concerning your final output you may do something like
$final = "";
//$output can be obtained by any method of the other answers,
//not just with the method i posted above
foreach($output as $key=>$value) {
$final .= $key . " ";
if(count($value) > 1) {
$final .= implode($value, " ") .", ";
} else {
$final .= $value . ", ";
}
}
$final = rtrim($final, ", ");
This will echo bim n-1, pow m-1 m-2, foo l-1 l-4 l-64.

Merging array in recursive function using 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);

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