After reading Split an array into an equal chunks and keep big chunk last and it's insufficiently challenging minimal verifiable example, I noticed in the lone, accepted answer that it was not robust enough to distribute excess elements to more than the last set so that the chunks of ascending minimal size were made balanced as much as possible.
For example, if the input array contained 8 elements and the minimum chunk size was 3
, the posted answer will create imbalanced subarrays with sizes of 2, 2, and 4 instead of 4 and 4. And given a chunk size of 3
and an 11-element array, the answer will create sizes of 2, 2, 2, 2, 3 instead of 3, 4, 4.
I would like a function which:
array_chunk()
, butFringe case handling: If the minimum chunk size is less than 1 or is greater than the count of the input array, throw an exception.
Test inputs and json encoded results (for brevity):
$minChunk = 3; $array = range(1, 8);
[[1,2,3,4],[5,6,7,8]]
$minChunk = 4; $array = range(1, 11);
[[1,2,3,4,5],[6,7,8,9,10,11]]
$minChunk = 2; $array = range(1, 5);
[[1,2],[3,4,5]]
$minChunk = 3; $array = range(1, 9);
[[1,2,3],[4,5,6],[7,8,9]]
$minChunk = 7; $array = range(1, 13);
[[1,2,3,4,5,6,7,8,9,10,11,12,13]]
$minChunk = 1; $array = range(1, 4);
[[1],[2],[3],[4]]
Here is an approach which will calculate the appropriate subarray sizes and consume the input array from the back while looping to populate the result array.
Code: (Demo with large battery of test cases)
function littleEndianMinChunk(array $array, int $minChunkSize): array
{
if ($minChunkSize < 1) {
throw new InvalidArgumentException('$minChunkSize must be 1 or greater');
}
if (count($array) < $minChunkSize) {
throw new InvalidArgumentException('$minChunkSize must not be less than the size of $array');
}
$result = [];
while ($array) {
$count = count($array);
$modulus = $count % $minChunkSize;
if (!$modulus) {
array_unshift($result, ...array_chunk($array, $minChunkSize));
break;
}
$expectedRemainingChunks = max(1, intdiv($count, $minChunkSize));
$sizeIncrease = ceil($modulus / $expectedRemainingChunks);
array_unshift($result, array_splice($array, -$minChunkSize - $sizeIncrease));
}
return $result;
}