'Chunk and transpose a flat array into rows with a specific number of columns

An array of values are provided in the order they should appear in columns. For example, the second value in the array should be displayed on a webpage beneath the first instead of on its right.

Task: Reorder the array so that the values are in the order they will be output in html. The data for the first row must be first in the output.

Example inputs:

$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; 
$cols = 2;

Example output:

[['A', 'E'], ['B','F'], ...]


Solution 1:[1]

Use array_chunk() to break the array up in to $cols:

$chunks = array_chunk($array, ceil(count($array) / $cols));

Which would give you:

array(array('A', 'B', 'C', 'D'), array('E', 'F', 'G'));

Then combine the values from each array where the keys match.

array_unshift($chunks, null);
$chunks = call_user_func_array('array_map', $chunks);

// array(array('A', 'E'), array('B', 'F'), array('C', 'G'), array('D', NULL))

Here's an example

Solution 2:[2]

You need to count offset and then iterate over an array:

$input = array('A', 'B', 'C', 'D', 'E', 'F', 'G');
$cols = 2;
$itemsCount = count($input);
$offset = ceil($itemsCount/$cols);

$result = array();
for($i = 0; $i < $itemsCount; ++$i) {
    if (isset($input[$i]) && isset($input[$i + $offset])) {
        $result[] = array($input[$i], $input[$i + $offset]);
    }
}

Solution 3:[3]

The modern functional equivalent of @billyonecan's approach uses the spread operator to transpose the data after it has been "chunked" to the correct size. (Demo)

$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; 
$cols = 2;

var_export(
    array_map(
        null,
        ...array_chunk($input, ceil(count($input) / 2))
    )
);
// [['A', 'E'], ['B', 'F'], ['C', 'G'], ['D', null]]

A classic loop alternative using a modulus calculation is also attractive because it doesn't generate the extra null element in the final set when the division doesn't come out even: (Demo)

$input = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; 
$cols = 2;

$rows = ceil(count($input) / $cols);
$result = [];
foreach ($input as $i => $value) {
    $result[$i % $rows][] = $value;
}
var_export($result);
// [['A', 'E'], ['B', 'F'], ['C', 'G'], ['D']]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 billyonecan
Solution 2 marian0
Solution 3