1

This question is in relation to this post How to distribute mysql result set in an multidimensional array of 4 arrays

I got the accepted answer but now i want to make a change to the code and i'm not having a lot of success...

Basically, from a mysql result set, i need to populate 4 arrays evenly distributed as much as possible from top to bottom... Chris Hayes provided a solutuon that works, but when i tested it today, i realize that it populates the array from left to rigth, and not from top to bottom...

How do i change the code so it populates the 4 arrays as much as possible from top to bottom ?

$i = 0;
$array_r = array( array(), array(), array(), array() );

while ($stmt->fetch()) {
    array_push($array_r[$i], array(... values ...));
    $i = ($i + 1) % 4;
}
Community
  • 1
  • 1
Marco
  • 2,687
  • 7
  • 45
  • 61

3 Answers3

4

final version without manipulating the input array at all:

for ($num = count($input), $offset = 0; $numBuckets > 0; $numBuckets -= 1, $num -= $bucketSize, $offset += $bucketSize) {
  $bucketSize = ceil($num / $numBuckets);
  $output[] = array_slice($input, $offset, $bucketSize);
}

pervious answer:

Try the following:

<?php
$input = range('A', 'Z'); // test input data
$output = array();        // the output container
$numBuckets = 4;          // number of buckets to fill

for (; $numBuckets > 0; $numBuckets -= 1) {
  $output[] = array_splice($input, 0, ceil(count($input) / $numBuckets));
}

print_r($output);

alternative version, without constant rechecking the length of the array

for ($num = count($input); $numBuckets > 0; $numBuckets -= 1, $num -= $bucketSize) {
  $bucketSize = ceil($num / $numBuckets);
  $output[] = array_splice($input, 0, $bucketSize);
}
Yoshi
  • 54,081
  • 14
  • 89
  • 103
  • tested and works perfectly... i even put a timer to test the speed and its fast... – Marco Aug 05 '13 at 18:31
  • 1
    @Marco As you mentioned speed, I added an alternative version, which removes the constant length check on the input array. – Yoshi Aug 05 '13 at 18:43
  • 1
    i had to put 80 decimals to start noticing a tiny diference: $elapsed = number_format($end - $start, 80); i think we can all agree that this is pretty fast!!!!!! thanks again dude! – Marco Aug 05 '13 at 18:59
1

This snippet should work for you:

<?php
$array= [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17];

$strays = count($array)%4;
$offset = 0;
$results = array();

for($x = 0; $x < 4; $x++){
    if ($x < $strays){
        $size = (floor(count($array)/4) + 1);
    } else {
        $size = (floor(count($array)/4));
    }
    $results[] = array_slice($array, $offset, $size);
    $offset+=$size;

}
print_r($results);
Orangepill
  • 24,500
  • 3
  • 42
  • 63
  • array_chunk doesnt work in this case coz the 4 arrays need to be evenly distributed as much as possible from top to bottom... If i have a result set of 18 rows, array_chunk populates the first array with 5 rows, the second array with 5 rows, the third array with 5 rows and the fourth array with 3 rows... It needs to be 5, 5, 4, 4 – Marco Aug 05 '13 at 16:45
  • @Marco I Understand what you are after now. – Orangepill Aug 05 '13 at 16:47
  • @Marco Updated with an alternative implementation – Orangepill Aug 05 '13 at 18:18
  • also tested this one and it also works and its equally as fast... thanks guys – Marco Aug 05 '13 at 18:36
  • Although it may work, having to hardcode 4 into the algorithm makes it more difficult in the future to switch to another number. – Mike Purcell Aug 05 '13 at 18:57
  • 1
    @mikepercell 4 can be substituted with any number or a variable. – Orangepill Aug 05 '13 at 19:04
  • @Orangepill: Sure, my point is, you have to make the change in multiple locations, vs the accepted answer, where you only need to change one var. – Mike Purcell Aug 05 '13 at 19:10
0

I've tested something and it seems to work... but it looks very spaghetti... please feel free to optimize the code. Thanks.

$num_rows = $stmt->num_rows; //number of records returned by the result set
$min_per_column = (int)($num_rows/4); //minimum records per column
$remainder = $num_rows % 4; //the remainder

$array_r = array(array(), array(), array(), array());
$i = 1;
$col = 0;

//how many records to populate before moving to the next array?
$rows = ($col < $remainder) ? $min_per_column + 1 : $min_per_column;

while ($stmt->fetch()) {
    array_push($array_r[$col], array($r_recordingid, $r_title, $r_subtitle, $r_seourl));
    $i++;

    //initialize values for new array
    if ($i > $rows) {
       $i = 1;
       $col++;
       $rows = ($col < $remainder) ? $min_per_column + 1 : $min_per_column;
    }
}
Marco
  • 2,687
  • 7
  • 45
  • 61