Reputation: 369
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)
Upvotes: 3
Views: 1470
Reputation: 21
You can prepend empty datas to your array, in sort of array_chunk be compliant to your need.
Then remove these prepended datas.
$chunk = 3;
$nbToPrepend = ($chunk - count($array) % $chunk);
$prepend = array_fill(0, $nbToPrepend, null);
$result = array_chunk(array_merge($prepend, $array), $chunk);
$result[0] = array_slice($result[0], $nbToPrepend);
Upvotes: 0
Reputation: 6167
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.
Upvotes: 3
Reputation: 42507
Functionally, the multiple array_reverse approach is quite understandable:
$chunk = array_reverse(array_map('array_reverse', array_chunk(array_reverse($array), 3)));
However, it's quite expensive, especially for larger arrays. Another way is to slice elements off the end of the array and prepend them to your chunked array:
$size = 3;
$chunk = array();
while (count($array) > 0) {
array_unshift($chunk, array_slice($array, -$size));
$array = array_slice($array, 0, -$size);
}
This works out about 20 times faster (over 100k iterations) for your array, and is about 1000 times faster for an array containing 600+ items.
Upvotes: 1
Reputation: 163457
You could reverse you array first using array_reverse, then use array_chunk. Then reverse the inner arrays, and reverse the outer arrays again:
$array = array(
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h'
);
$array = array_reverse($array);
$chunk = array_chunk($array, 3);
$array = array_map('array_reverse', $chunk);
print_r(array_reverse($array));
Result
Array
(
[0] => Array
(
[0] => a
[1] => b
)
[1] => Array
(
[0] => c
[1] => d
[2] => e
)
[2] => Array
(
[0] => f
[1] => g
[2] => h
)
)
Upvotes: 1