Stefano Radaelli
Stefano Radaelli

Reputation: 1118

php array_chunk with balanced number of elements

I have a need to split an array into several chunks each of them with same number of elements (even repeated across different chunks) balanced across the output

So, for example and starting from an array such this:

$input = array(1,2,3,4,5,6,7,8,9,10,11);

I'm trying to develop a function that accept the input array and the number of elements expected on each chunk. So for example [ balanced_chunk($input, 3) ]

should gets me

0 => array(1,2,3)
1 => array(4,5,6)
2 => array(6,7,8)         #-- Value 6 is repeated
3 => array(9,10,11)

as long as [ balanced_chunk($input, 5) ]

should gets me

0 => array(1,2,3,4,5)
1 => array(4,5,6,7,8)     #-- Value 4,5 are repeated
2 => array(7,8,9,10,11)   #-- Value 7,8 are repeated

and so on

To start I've developed such function

function balanced_chunk($input, $size) {
    $step = ceil(count($input) / $size);
    $chunks = range(0, count($input), count($input) / $step);
    reset($chunks);
    while (list(,$start) = each($chunks)) {
            $start = (fmod($start, 1) <= 0.5 ? floor($start) : ceil($start));
            $clist[] = array_slice($input, $start, $size, true);
    }
    return($clist);
}

but for a reason that at the moment I miss, it gets me such output:

[0] => Array (1,2,3,4,5)
[1] => Array (5,6,7,8,9)     #-- this element should instead start from 4...
[2] => Array (8,9,10,11)     #-- last element contains only 4 value

Just to make a better example consider the input array [ a,b,c,d,e,f,g,h,i,l,m,n,o,p ]

a balanced chunk with 5 elements each has to be

[ a,b,c,d,e ]
          [ f,g,h,i,l ]
                  [ l,m,n,o,p ] #-- letter 'l' is repeated twice on 3rd result

or (as valid alternative)

[ a,b,c,d,e ] 
        [ e,f,g,h,i ]           #-- letter 'e' is repeated twice on 2nd result
                    [ l,m,n,o,p ]

a balanced chunk with 8 elements each has to be

[ a,b,c,d,e,f,g,h ] 
            [ g,h,i,l,m,n,o,p ]  #-- letter 'g','h' are repeated twice

I'm stucked! After several trial by myselft I'm not able to find out how to solve such problem.

Upvotes: 3

Views: 2479

Answers (2)

Stefano Radaelli
Stefano Radaelli

Reputation: 1118

For the moment, waiting to find out a "smarter" approach I've found this solution:

function balanced_chunk($input, $size) {
    $chunks   = ceil(count($input) / $size);
    $step     = count($input) / $chunks;
    $chunklist = array();
    for ($i = 0; $i < count($input); $i += $step) {
        $chunk = array_slice($input, floor($i), $size);
        if (count($chunk) < $size)  $chunk = array_slice($input, $size * -1, $size, true);
        $chunklist[] = $chunk;
    }
    return($chunklist);
}

That means that for example... Ex #1: 11 elements split in chunk of 3 each:

$split = balanced_chunk(range(1, 11), 3));
/*
[ 1,2,3 ]
    [ 3,4,5 ][ 6,7,8 ][ 9,10,11 ]

In such case the fx needs to be better tuned as a better balanced output
has instead to be

[ 1,2,3 ][ 4,5,6 ]
             [ 6,7,8 ][ 9,10,11 ]
*/

Ex #2: 11 elements split in chunk of 4 each:

$split = balanced_chunk(range(1, 11), 4));
/*
[ 1,2,3,4 ]
      [ 4,5,6,7 ][ 8,9,10,11 ]

In such case the given output is exactly comparable with the alternative

[ 1,2,3,4 ][ 5,6,7,8 ]
                 [ 8,9,10,11 ]
*/

Ex #3: 11 elements split in chunk of 5 each:

$split = balanced_chunk(range(1, 11), 5));
/*
[ 1,2,3,4,5 ]
      [ 4,5,6,7,8 ]
            [ 7,8,9,10,11 ]
*/

Ex #4: 11 elements split in chunk of 7 each:

$split = balanced_chunk(range(1, 11), 7));
/*
[ 1,2,3,4,5,6,7 ]
        [ 5,6,7,8,9,10,11 ]
*/

I welcome tips or suggestion to improve this.

Upvotes: 0

kohloth
kohloth

Reputation: 914

You have probably moved on to other things now! But here is my way of doing this.

function balanced_chunk($input, $size)
{
    $len = count($input);
    $chunkSize = ceil($len / $size);
    $o = [];
    $i = 1;
    $k = 0;
    foreach ($input as $elem)
    {
        $o[$k][$i] = $elem;
        $k = ($i % $chunkSize == 0) ? $k+1 : $k;
        $i++;
    }
    return $o;
}

Upvotes: 1

Related Questions