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);
}
?>
Related
I have long string which I split after each 4th char. After that I want to take 3 random of them and show how many times are in the array.
What I have is
$string = "AAAAAAABAAACAAADAAAEAAAFAAAGAAAHAAAIAAAJAAAKAAALAAAMAAANAAAOAAAPAAAQAAARAAASAAATAAAUAAAVAAAWAAAXAAAYAAAZAAAaAAAbAAAcAAAdAAAeAAAfAAAgAAAhAAAiAAAjAAAkAAAlAAAmAAAnAAAoAAApAAAqAAArAAAsAAAtAAAuAAAvAAAwAAAxAAAyAAAzAABAAABBAABCAABDAABEAABFAABGAABHAABIAABJAABKAABLAABMAABNAA";
$segmentLength = 3;
$totalLength = strlen($string);
for ($i = 0; $i < $totalLength; $i += $segmentLength) {
$result[] = substr($string, min($totalLength - $segmentLength, $i), $segmentLength);
}
print_r(array_rand(array_count_values($result), 4));
array_count_values($result) output is
Array
(
[AAA] => 19
[ABA] => 1
[AAC] => 1
........
[AAL] => 1
[MAA] => 1
[AAB] => 4
)
I'm trying with print_r(array_rand(array_count_values($result), 4)); to output
Array
(
[AAA] => 19
[ABA] => 1
[AAC] => 1
[AAB] => 4
)
or
Array
(
[ABA] => 1
[AAC] => 1
[AAL] => 1
[MAA] => 1
)
instead I get
Array
(
[0] => AHA
[1] => AAa
[2] => zAA
[3] => BGA
)
...
Array
(
[0] => GAA
[1] => AxA
[2] => CAA
[3] => BGA
)
... so on
You could store the result of array_count_values($result); to a variable and then get a random set of keys from that result. Then loop through that random list of keys and generate your desired output. For example:
$string = "AAAAAAABAAACAAADAAAEAAAFAAAGAAAHAAAIAAAJAAAKAAALAAAMAAANAAAOAAAPAAAQAAARAAASAAATAAAUAAAVAAAWAAAXAAAYAAAZAAAaAAAbAAAcAAAdAAAeAAAfAAAgAAAhAAAiAAAjAAAkAAAlAAAmAAAnAAAoAAApAAAqAAArAAAsAAAtAAAuAAAvAAAwAAAxAAAyAAAzAABAAABBAABCAABDAABEAABFAABGAABHAABIAABJAABKAABLAABMAABNAA";
$segmentLength = 3;
$totalLength = strlen($string);
for ($i = 0; $i < $totalLength; $i += $segmentLength) {
$result[] = substr($string, min($totalLength - $segmentLength, $i), $segmentLength);
}
$countedValues = array_count_values($result);
$randValues = array_rand($countedValues, 4);
$output = [];
for ($i = 0; $i < count($randValues); $i++) {
$key = $randValues[$i];
$output[$key] = $countedValues[$key];
}
print_r($output);
I fetch data from my database and it returns 6 rows. I loop over them add them to a temporary array and then every 2 iterations I add them to a parent array so I will know have an array with sub arrays grouped by 2. Below, as you can see, I echo out each iteration for 6 results. My grouped array is only showing 2 groups of 2 when it should be 3 groups of 2. What am I doing wrong?
Note: I checked the data and the first 2 groups are correct data, but the last 2 rows are missing.
// group entries into subgroups of 2
$buffer = array();
$entries = array();
for( $i = 0; $i < $journal_entries_count; $i++ )
{
if( $i % 2 == 0 && $i > 0 )
{
$entries[] = $buffer;
unset( $buffer );
$buffer = array();
}
$buffer[] = $journal_entries[ $i ];
echo $i, '<br />';
}
0
1
2
3
4
5
Array
(
[0] => Array
(
[0] => Array
(
[journal_entry_id] => 196
[journal_entry_date] => 2014-10-24 20:01:44
[scoring_type_id] => 1
[score] => 2662.00
[wod_title] => yyyyy
[wod_date] => 2014-09-12
[strength] =>
[repscheme] =>
[benchmark] => Annie
)
[1] => Array
(
[journal_entry_id] => 197
[journal_entry_date] => 2014-10-24 20:01:44
[scoring_type_id] => 1
[score] => 196.00
[wod_title] => yyyyy
[wod_date] => 2014-09-12
[strength] =>
[repscheme] =>
[benchmark] => Badger
)
)
[1] => Array
(
[0] => Array
(
[journal_entry_id] => 195
[journal_entry_date] => 2014-10-24 20:00:19
[scoring_type_id] => 1
[score] => 300.00
[wod_title] => Koala Bear WOD
[wod_date] => 2014-10-21
[strength] =>
[repscheme] =>
[benchmark] => Amanda
)
[1] => Array
(
[journal_entry_id] => 194
[journal_entry_date] => 2014-10-24 20:00:19
[scoring_type_id] => 7
[score] => 5.20
[wod_title] => Koala Bear WOD
[wod_date] => 2014-10-21
[strength] => Back Squat
[repscheme] => 10RM
[benchmark] =>
)
)
)
Solution?
I'm not marking it as a solution yet because I'm not sure it will work in all cases,
but loop at each iteration it never hits the last one.
0 = skip - add
1 = skip - add
2 = add - add
3 = skip - add
4 = add - add
5 = skip - add
I added $journal_entries_count + 1 and the results are now correct.
Thoughts?
If $journal_entries_count is 6, then at the end of your loop, $buffer will contain two rows, but it won't have been added to $entries.
You need to add a final
$entries[] = $buffer;
after the loop. Alternatively, you could use array_chunk:
$entries = array_chunk($journal_entries, 2);
can you try it with some simpler code like this and see how you go.
$entries = array();
$journal_entries[] = 1;
$journal_entries[] = 2;
$journal_entries[] = 3;
$journal_entries[] = 4;
$journal_entries[] = 5;
while (count($journal_entries)){
$entries[] = array_slice($journal_entries,0,2);
$journal_entries = array_slice($journal_entries,2);
}
print_r($entries);
You are missing the last 2 entries because you don't add the buffer from the last loop.
You need to update your code and after the foreach loop, check if the buffer is empty or not. If it's not empty then add it to the final array.
You say that for $journal_entries_count + 1 it works, because you actually run the loop one more time and adds the final buffer from the "true" last loop.
The end code should be something like this:
$buffer = array();
$entries = array();
for( $i = 0; $i < $journal_entries_count; $i++ ) {
if( $i % 2 == 0 && $i > 0 ) {
$entries[] = $buffer;
unset( $buffer );
$buffer = array();
}
$buffer[] = $journal_entries[ $i ];
echo $i, '<br />';
}
// add any leftover buffer data
if(count($buffer) > 0) {
$entries[] = $buffer;
}
I have the following array:
[ratings] => Array
(
[0] => 3
[1] => 3
[2] => 2
[3] => 3
[4] => 3
[5] => 1
[6] => 3
[7] => 4
[8] => 5
)
What would be the best and fastest way to get the the percentage of each rating. For example there are 9 ratings now, and 5 ratings of "3", so the percentage of rating "3" is 55.55%.
although he probably has something already, this is what I came up with.
<?php
$array = array(3,3,2,3,3,1,3,4,5);
function array_avg($array, $round=1){
$num = count($array);
return array_map(
function($val) use ($num,$round){
return array('count'=>$val,'avg'=>round($val/$num*100, $round));
},
array_count_values($array));
}
$avgs = array_avg($array);
/*
* You can access any average/count like:
* echo "The count of 3 is: {$avgs[3]['count']}";
* echo "The average of 3 is: {$avgs[3]['avg']}";
*/
echo '<pre>'.print_r($avgs,1).'</pre>';
Output:
Array
(
[3] => Array
(
[count] => 5
[avg] => 55.6
)
[2] => Array
(
[count] => 1
[avg] => 11.1
)
[1] => Array
(
[count] => 1
[avg] => 11.1
)
[4] => Array
(
[count] => 1
[avg] => 11.1
)
[5] => Array
(
[count] => 1
[avg] => 11.1
)
)
http://codepad.viper-7.com/yD9CQm
function findPercentage($r, $ratings){
$arr = array_count_values($ratings);
return $arr[$r]/count($ratings) * 100;
}
As commented, you can make use of the array_count_values and process with count with a simple iteration.
In my code-example I wrap this into a function of it's own:
$ratings = [3,3,2,3,3,1,3,4,5];
$percentages = function($ratings) {
$total = count($ratings);
$percentages = [];
foreach(array_count_values($ratings) as $value => $count) {
$percentages[$value] = $count / $total;
}
return $percentages;
};
print_r($percentages($ratings));
Output (Demo):
Array (
[3] => 0.55555555555556
[2] => 0.11111111111111
[1] => 0.11111111111111
[4] => 0.11111111111111
[5] => 0.11111111111111
)
I hope this demonstrates it fairly well. And again (for the fun):
print_r($percentages(array_map('strval', $percentages($ratings))));
(array_count_values() can only count STRING and INTEGER values)
Output:
Array (
[0.55555555555556] => 0.2
[0.11111111111111] => 0.8
)
$avg = array_sum($a)/count($a)
in Javascript:
var a = [1,2,3,4,5,6];
var avg = a.reduce(function(a,b){ return a+b })/a.length;
// $ratings is your array
function findPercentage($r, $ratings){
$count = 0; // count number of particular ratings
foreach ($ratings as $i){
if ($i == $r) $count++;
}
return $count/count($ratings) * 100;
}
example:
echo findPercentages(3, $ratings);
$rating = array(3, 3, 5, 5, 3, 4);
$value = 0;
foreach ($rating as $i) {
$value += $i;
}
$percentage = $value / count($rating);
echo $percentage;
==
UPDATE
I wrote small test:
$rating = array();
echo "create array".PHP_EOL;
for ($i = 0; $i < 100000; $i++) {
$rating[] = rand(1, 5);
}
echo "foreach algorithm: ".PHP_EOL;
$time = microtime();
$value = 0;
foreach ($rating as $i) {
$value += $i;
}
$percentage = $value / count($rating);
echo $percentage.PHP_EOL;
echo "time is ".(microtime() - $time).PHP_EOL;
echo "array_sum algorithm: ".PHP_EOL;
$time = microtime();
$avg = array_sum($rating)/count($rating);
echo "time is ".(microtime() - $time).PHP_EOL;
and result:
create array
foreach algorithm:
2.99924
time is 0.017117
array_sum algorithm:
time is 0.002819
Answer: use algorithm that wrote user #Reflective, use function array_sum
I try to write a script and a problem. Can you let me know if you know how i can do this or ask someone if they know how can this be possibe.
Max numbers which can be selected 1 to 20 numbers. it can loop and select any number between 1-20
ignore these numbers e.g. 1,2,4,6,9,12 this will be array which can change.
each array line can have upto 4 numbers
Each array line needs to be unique
5.I need to have around 10 arrays unique
Max 2 numbers can match previous numbers see below.
How can i go about doing this. Any help would be great.
e.g.
Array(
[0] => Array
(
[0] => 3
[1] => 16
[2] => 22
[3] => 24
)
[1] => Array
(
[0] => 3
[1] => 16
[2] => 7
[3] => 13
)
[2] => Array
(
[0] => 20
[1] => 17
[2] => 10
[3] => 18
)
)
This not allow as some array match each other
Array(
[0] => Array
(
[0] => 3
[1] => 16
[2] => 22
[3] => 24
)
[1] => Array - cant have this as 3 of the numbers matchs the previous array.only two numbers can match.
(
[0] => 3
[1] => 16
[2] => 22
[3] => 13
)
[2] => Array
(
[0] => 20
[1] => 17
[2] => 10
[3] => 18
)
)
Thank you.
This seems to satisfy your conditions: http://codepad.viper-7.com/WHkQeD
<?php
$num_arrays = 10; $num_elements = 4;
$min = 1; $max = 20;
$exclude_numbers = array( 1, 4, 6); // Add numbers here to exclude
$answer = array();
for( $i = 0; $i < $num_arrays; $i++)
{
$answer[$i] = array();
for( $j = 0; $j < $num_elements; $j++)
{
do
{
$current = rand( $min, $max);
// If the previous array exists and there are more than two common elements when we add the $current element, continue
if( isset( $answer[$i-1]) && count( array_intersect( $answer[$i-1], array_merge( $answer[$i], array( $current))) > 2)
{
continue;
}
} while( in_array( $current, $exclude_numbers) || in_array( $current, $answer[$i]));
$answer[$i][$j] = $current;
}
}
var_dump( $answer);
Edit: Here is a complete solution that satisfies all of your criteria.
Demo
<?php
$num_arrays = 10; $num_elements = 4;
$min = 1; $max = 20;
$exclude_numbers = array( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
$answer = array();
for( $i = 0; $i < $num_arrays; $i++)
{
$answer[$i] = array();
for( $j = 0; $j < $num_elements; $j++)
{
do
{
// Get a random element
$current = rand( $min, $max);
$new_array = array_merge( $answer[$i], array( $current));
// If the previous array has more than two common elements (because of the added $current), get a new $current
if( isset( $answer[$i-1]) && count( array_intersect( $answer[$i-1], $new_array)) > 2)
{
$answer[$i] = array_diff( $new_array, $answer[$i-1]);
$j = count( $answer[$i]) - 1;
continue;
}
} while( in_array( $current, $exclude_numbers) || in_array( $current, $answer[$i]));
$answer[$i][$j] = $current;
// If the array is complete, we need to check for unique arrays
if( count( $answer[$i]) == $num_elements)
{
$k = $i - 1;
while( $k >= 0)
{
if( count( array_diff( $answer[$k], $answer[$i])) == 0)
{
// This array is the same as a previous one, start over
$answer[$i] = array();
$j = -1;
break;
}
$k--;
}
// Optionally sort each array
sort( $answer[$i]);
}
}
}
var_dump( $answer);
somthing like:
function generate_list($max, $forbidden)
{
$list = array();
while(count($list) < 4)
{
$new = rand(1, $max);
if(in_array($new, $forbidden))
{
continue;
}
$list[] = $new;
$forbidden[] = $new;
}
return $list;
}
function count_max_same($new_list, $old_lists)
{
$max_same = 0;
foreach($old_lists as $current_list)
{
$max_same = max($max_same, count(array_intersect($new_list, $old_lists)));
}
return $max_same;
}
function generate_unique_lists($count_of_lists, $max, $forbidden, $max_same = 2, $max_tries = 1000)
{
$lists = array();
while($max_tries-- AND count($lists) < $count_of_lists)
{
$new_list = generate_list($max, $forbidden);
if(count_max_same($new_list, $lists) <= $max_same)
{
$lists[] = $new_list;
}
}
return $lists;
}
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.