Search code examples
phparrayschunks

Move elements using array_chunk with PHP


I have a basic array in which I am using array_chunk to divide it into 3 elements.

$array = array(
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'
);

$chunk = array_chunk($array, 3);

The result is as follows

[
   [
     "a",
     "b",
     "c"
   ],
   [
     "d",
     "e",
     "f"
   ],
   [
     "g",
     "h"
   ]
]

(Las chunk have 2 elements)

In case the last "chunk" has only 2 elements, how can I move down an element of the first chunk so that the first element has 2?

It should look like this:

[
   [
     "a",
     "b",
   ],
   [
     "c"
     "d",
     "e",
   ],
   [
     "f"
     "g",
     "h
   ]
]

(First chunk have 2 elements)


Solution

  • The easiest way are mutliple executions of erray_reverse: first reverse the entire array, then split, then reverse every chunk and then, lastly, the array of chunks.

    As a one-liner, it loooks like this: $chunk = array_reverse(array_map('array_reverse', array_chunk(array_reverse($array), 3)));

    Mind however that reversing an array is an expensive operation, so if you array is acutally alrger than in your example, this is not a recommended way.


    More effective but also more code: Calculate the number of elements need to be in the first chunk using modulo: $first_chunk_size = count($array) % 3;

    Next, to avoid an empty array if array size is a multiple of chunk size, correct the chunk size if modulo yields 0: $first_chunk_size = $first_chunk_size == 0 ? 3 : $first_chunk_size;

    then, cut off the first part: $first_chunk = array_slice($array, 0, $first_chunk_size);

    next, split the rest of the array: $chunks = array_chunk(array_slice($array,$first_chunk_size),3);

    then combine the first chunk and the other chunks into one array: array_unshift($chunks, $first_chunk);

    Full code of the second approach:

    $array = [
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'
    ];
    
    $first_chunk_size = count($array) % 3;
    $first_chunk_size = $first_chunk_size == 0 ? 3 : $first_chunk_size;
    
    $first_chunk = array_slice($array, 0, $first_chunk_size);
    $chunks = array_chunk(array_slice($array,$first_chunk_size),3);
    array_unshift($chunks, $first_chunk);
    
    var_dump($chunks);
    

    (obviously this code can be simplified by not doing everything step-by-step)


    EDIT: Having read your comments to the other replies, you can modify this approach a little and turn it into a recusrive function. With some code-cleanup,. it may look like this:

    $array = [
        'a', 'b', 'c', 'd', 'e', 'f', 'g'
    ];
    
    function custom_array_chunk ($array) {
        $first_chunk_size = count($array) % 3;
        if ($first_chunk_size == 0) {
            $chunks = array_chunk($array, 3);
        } else {
            $chunks = custom_array_chunk(array_slice($array,2));
            array_unshift($chunks, array_slice($array, 0, 2));
        }
        return $chunks;
    }
    
    var_dump(custom_array_chunk($array));
    

    This will work for both cases, 1 and 2 elements "left over" and will yield exactly what you told us.

    Demo