Reputation: 13
I have a 2d array of "packs" with their own specified size in centimeters. I need to optimally distribute these packs into a new 3d array to represent pallets of packs which each have a maximum capacity of 265cm.
Current code which works with a 1d array of sizes:
$default_cc_height_fa = 265; // size of the pallet in cm
$sh_array = [50, 45, 30, 60, 70, 80]; // array of packs
// sort the array of packs in decreasing order of size
usort($sh_array, function($a, $b) {
return $b - $a;
});
// initialize the array of pallets
$mix_cc_array = [];
// iterate through the array of packs
foreach ($sh_array as $pack) {
// try to fit the pack into an existing pallet
$packed = false;
foreach ($mix_cc_array as &$pallet) {
if ($pack <= $default_cc_height_fa - array_sum($pallet)) {
$pallet[] = $pack;
$packed = true;
break;
}
}
// if the pack does not fit into any existing pallet, create a new one
if (!$packed) {
$mix_cc_array[] = [$pack];
}
}
print_r($mix_cc_array);
How is it possible to adjust the above code to accommodate a 2d array like this:
$sh_array = [
['id_product' => 13, 'size' => 50],
['id_product' => 13, 'size' => 45],
['id_product' => 13, 'size' => 30],
['id_product' => 13, 'size' => 60],
['id_product' => 13, 'size' => 70],
['id_product' => 13, 'size' => 80]
];
// array of array of packs
Of course, I need to manage the sizes, but I need entire rows of data (packs) to be pushed into the subarrays (pallets).
Upvotes: 0
Views: 73
Reputation: 48001
The only difference between my earlier answer and this answer is how to sort and count the array data. The algorithm remains the same.
Code: (Demo)
$pallet_limit = 111;
$packs = [
['id_product' => 13, 'size' => 50],
['id_product' => 13, 'size' => 45],
['id_product' => 13, 'size' => 30],
['id_product' => 13, 'size' => 60],
['id_product' => 13, 'size' => 70],
['id_product' => 13, 'size' => 80]
];
usort($packs, fn($a, $b) => $b["size"] <=> $a["size"]);
$pallets = [];
foreach ($packs as $pack) {
foreach ($pallets as &$pallet) {
if ((array_sum(array_column($pallet, 'size')) + $pack["size"]) <= $pallet_limit) {
$pallet[] = $pack;
continue 2;
}
}
$pallets[] = [$pack];
}
var_export($pallets);
Upvotes: 1
Reputation: 11255
With minor modifications, we can loop through an array of packs that have both id
and size
attributes. To make the comparison between the size of the current pack
and the maximum height constant, we can also add attributes to the pack
to accumulate everything.
Finally, because I was interested in exiting both loops, I used continue 2
although you could keep your original $packed = false;
approach as well.
<?php
const DEFAULT_CC_HEIGHT_FA = 265; // size of the pallet in cm
// define array of products to add
$sh_array = [["id_product" => 13, "size" => 50],
["id_product" => 13, "size" => 45],
["id_product" => 13, "size" => 30],
["id_product" => 13, "size" => 60],
["id_product" => 13, "size" => 70],
["id_product" => 13, "size" => 80]];
// sort the array of packs in decreasing order of size
usort($sh_array, function($a, $b) {
return $b["size"] - $a["size"];
});
// initialize the array of pallets
$mix_cc_array = [];
// iterate through the array of packs
foreach ($sh_array as $listRow) {
// try to fit the pack into an existing pallet
foreach ($mix_cc_array as &$pallet) {
$newHeight = $listRow["size"] + $pallet["totalHeight"];
if ($newHeight <= DEFAULT_CC_HEIGHT_FA) {
// add new pack to this pallet
array_push($pallet["pallets"],$listRow);
// update accumulators
$pallet["palletsStored"] += 1;
$pallet["totalHeight"] = $newHeight;
// continue the outer loop
continue 2;
}
}
// if the pack does not fit into any existing pallet, create a new one
$mix_cc_array[] = array("totalHeight"=> $listRow["size"],
"palletsStored" => 1, "pallets" => [$listRow]);
}
print_r($mix_cc_array);
Upvotes: 1