PHP - Packing widgets into the fewest number of boxes, plus minimum order quantityWhat is the most memory...

Calculus Optimization - Point on graph closest to given point

least quadratic residue under GRH: an EXPLICIT bound

Is it possible to make sharp wind that can cut stuff from afar?

How can bays and straits be determined in a procedurally generated map?

Concept of linear mappings are confusing me

Could a US political party gain complete control over the government by removing checks & balances?

What Brexit solution does the DUP want?

XeLaTeX and pdfLaTeX ignore hyphenation

Copycat chess is back

What do you call something that goes against the spirit of the law, but is legal when interpreting the law to the letter?

Non-Jewish family in an Orthodox Jewish Wedding

What does "enim et" mean?

How do we improve the relationship with a client software team that performs poorly and is becoming less collaborative?

"which" command doesn't work / path of Safari?

What typically incentivizes a professor to change jobs to a lower ranking university?

Draw simple lines in Inkscape

New order #4: World

Japan - Any leeway for max visa duration due to unforeseen circumstances?

Is there a minimum number of transactions in a block?

Is there really no realistic way for a skeleton monster to move around without magic?

How is the relation "the smallest element is the same" reflexive?

Extreme, but not acceptable situation and I can't start the work tomorrow morning

Why has Russell's definition of numbers using equivalence classes been finally abandoned? ( If it has actually been abandoned).

Why don't electron-positron collisions release infinite energy?



PHP - Packing widgets into the fewest number of boxes, plus minimum order quantity


What is the most memory efficient way to load big arrays into PHP script?Finding the minimum number of required deletions to have a non-repeating stringFind the minimum number of operations to convert 1 into n, and print the sequence of numbersFinding the minimum number of swaps to sort a listPlace arithmetic signs in correct order to get the numberPHP code to insert phone number and IP address into a table if not already present






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







2












$begingroup$


The problem is this:



A company supplies widgets in a set of pack sizes:




  • 250

  • 500

  • 1000

  • 2000

  • 5000


Customers can order any number of widgets, but the following rules apply:




  • Only whole packs can be sent and …

  • No more widgets than necessary should be sent and …

  • The fewest packs possible should be sent


Some examples showing the number of widgets ordered and the required pack quantities and sizes to correctly fulfill the order:




  • 1 (1 x 250)

  • 251 (1 x 500)

  • 501 (1 x 500 and 1 x 250)

  • 12001 (2 x 5000 and 1 x 2000 and 1 x 250)


I’ve looked at some algorithms (greedy coin change, LAFF, etc.) as these seem to provide similar solutions, but can’t seem to see how to adapt them to the above.



For example:



<?php

function countWidgets($amount)
{
$packs = array(5000, 2000, 1000, 500,
250);
$packCounter = array(0, 0, 0, 0, 0);
$packsCount = count($packs);

// loop packs
for ($i = 0; $i < $packsCount; $i++)
{
if ($amount >= $packs[$i])
{
$packCounter[$i] = intval($amount /
$packs[$i]);
$amount = $amount -
$packCounter[$i] *
$packs[$i];
}
}

// if remainder
if ($amount > 0) {
// and if smallest pack size populated
if ($packCounter[4] == 1) {
// clear smallest pack size
$packCounter[4] = 0;
// increment next biggest pack size
$packCounter[3] += 1;
} else {
// increment smallest pack size
$packCounter[4] +=1;
}
}


// Print packs
echo ("Pack ->"."n");
for ($i = 0; $i < $packsCount; $i++)
{
if ($packCounter[$i] != 0)
{
echo ($packs[$i] . " : " .
$packCounter[$i] . "n");
}
}
}

$amount = 251;
countWidgets($amount);









share|improve this question









New contributor




Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$












  • $begingroup$
    I don't see what the problem is here? You start by trying the biggest pack, until there are fewer widgets left than the size of that pack. Then you move to a smaller pack, and so on, until the smallest pack. If there are some ordered widget left, after all of this, you add one smallest pack. That's it. If you can do it by hand, then you can certainly program it.
    $endgroup$
    – KIKO Software
    Apr 2 at 11:08












  • $begingroup$
    Can you confirm that the code is complete and that it functions correctly? If so, I recommend that you edit to add a summary of the testing (ideally as reproducible unit-test code). If it's not working, it isn't ready for review (see help center) and the question may be deleted.
    $endgroup$
    – Toby Speight
    Apr 2 at 11:46


















2












$begingroup$


The problem is this:



A company supplies widgets in a set of pack sizes:




  • 250

  • 500

  • 1000

  • 2000

  • 5000


Customers can order any number of widgets, but the following rules apply:




  • Only whole packs can be sent and …

  • No more widgets than necessary should be sent and …

  • The fewest packs possible should be sent


Some examples showing the number of widgets ordered and the required pack quantities and sizes to correctly fulfill the order:




  • 1 (1 x 250)

  • 251 (1 x 500)

  • 501 (1 x 500 and 1 x 250)

  • 12001 (2 x 5000 and 1 x 2000 and 1 x 250)


I’ve looked at some algorithms (greedy coin change, LAFF, etc.) as these seem to provide similar solutions, but can’t seem to see how to adapt them to the above.



For example:



<?php

function countWidgets($amount)
{
$packs = array(5000, 2000, 1000, 500,
250);
$packCounter = array(0, 0, 0, 0, 0);
$packsCount = count($packs);

// loop packs
for ($i = 0; $i < $packsCount; $i++)
{
if ($amount >= $packs[$i])
{
$packCounter[$i] = intval($amount /
$packs[$i]);
$amount = $amount -
$packCounter[$i] *
$packs[$i];
}
}

// if remainder
if ($amount > 0) {
// and if smallest pack size populated
if ($packCounter[4] == 1) {
// clear smallest pack size
$packCounter[4] = 0;
// increment next biggest pack size
$packCounter[3] += 1;
} else {
// increment smallest pack size
$packCounter[4] +=1;
}
}


// Print packs
echo ("Pack ->"."n");
for ($i = 0; $i < $packsCount; $i++)
{
if ($packCounter[$i] != 0)
{
echo ($packs[$i] . " : " .
$packCounter[$i] . "n");
}
}
}

$amount = 251;
countWidgets($amount);









share|improve this question









New contributor




Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$












  • $begingroup$
    I don't see what the problem is here? You start by trying the biggest pack, until there are fewer widgets left than the size of that pack. Then you move to a smaller pack, and so on, until the smallest pack. If there are some ordered widget left, after all of this, you add one smallest pack. That's it. If you can do it by hand, then you can certainly program it.
    $endgroup$
    – KIKO Software
    Apr 2 at 11:08












  • $begingroup$
    Can you confirm that the code is complete and that it functions correctly? If so, I recommend that you edit to add a summary of the testing (ideally as reproducible unit-test code). If it's not working, it isn't ready for review (see help center) and the question may be deleted.
    $endgroup$
    – Toby Speight
    Apr 2 at 11:46














2












2








2





$begingroup$


The problem is this:



A company supplies widgets in a set of pack sizes:




  • 250

  • 500

  • 1000

  • 2000

  • 5000


Customers can order any number of widgets, but the following rules apply:




  • Only whole packs can be sent and …

  • No more widgets than necessary should be sent and …

  • The fewest packs possible should be sent


Some examples showing the number of widgets ordered and the required pack quantities and sizes to correctly fulfill the order:




  • 1 (1 x 250)

  • 251 (1 x 500)

  • 501 (1 x 500 and 1 x 250)

  • 12001 (2 x 5000 and 1 x 2000 and 1 x 250)


I’ve looked at some algorithms (greedy coin change, LAFF, etc.) as these seem to provide similar solutions, but can’t seem to see how to adapt them to the above.



For example:



<?php

function countWidgets($amount)
{
$packs = array(5000, 2000, 1000, 500,
250);
$packCounter = array(0, 0, 0, 0, 0);
$packsCount = count($packs);

// loop packs
for ($i = 0; $i < $packsCount; $i++)
{
if ($amount >= $packs[$i])
{
$packCounter[$i] = intval($amount /
$packs[$i]);
$amount = $amount -
$packCounter[$i] *
$packs[$i];
}
}

// if remainder
if ($amount > 0) {
// and if smallest pack size populated
if ($packCounter[4] == 1) {
// clear smallest pack size
$packCounter[4] = 0;
// increment next biggest pack size
$packCounter[3] += 1;
} else {
// increment smallest pack size
$packCounter[4] +=1;
}
}


// Print packs
echo ("Pack ->"."n");
for ($i = 0; $i < $packsCount; $i++)
{
if ($packCounter[$i] != 0)
{
echo ($packs[$i] . " : " .
$packCounter[$i] . "n");
}
}
}

$amount = 251;
countWidgets($amount);









share|improve this question









New contributor




Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$




The problem is this:



A company supplies widgets in a set of pack sizes:




  • 250

  • 500

  • 1000

  • 2000

  • 5000


Customers can order any number of widgets, but the following rules apply:




  • Only whole packs can be sent and …

  • No more widgets than necessary should be sent and …

  • The fewest packs possible should be sent


Some examples showing the number of widgets ordered and the required pack quantities and sizes to correctly fulfill the order:




  • 1 (1 x 250)

  • 251 (1 x 500)

  • 501 (1 x 500 and 1 x 250)

  • 12001 (2 x 5000 and 1 x 2000 and 1 x 250)


I’ve looked at some algorithms (greedy coin change, LAFF, etc.) as these seem to provide similar solutions, but can’t seem to see how to adapt them to the above.



For example:



<?php

function countWidgets($amount)
{
$packs = array(5000, 2000, 1000, 500,
250);
$packCounter = array(0, 0, 0, 0, 0);
$packsCount = count($packs);

// loop packs
for ($i = 0; $i < $packsCount; $i++)
{
if ($amount >= $packs[$i])
{
$packCounter[$i] = intval($amount /
$packs[$i]);
$amount = $amount -
$packCounter[$i] *
$packs[$i];
}
}

// if remainder
if ($amount > 0) {
// and if smallest pack size populated
if ($packCounter[4] == 1) {
// clear smallest pack size
$packCounter[4] = 0;
// increment next biggest pack size
$packCounter[3] += 1;
} else {
// increment smallest pack size
$packCounter[4] +=1;
}
}


// Print packs
echo ("Pack ->"."n");
for ($i = 0; $i < $packsCount; $i++)
{
if ($packCounter[$i] != 0)
{
echo ($packs[$i] . " : " .
$packCounter[$i] . "n");
}
}
}

$amount = 251;
countWidgets($amount);






php algorithm






share|improve this question









New contributor




Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited Apr 2 at 13:39







Matthew French













New contributor




Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Apr 2 at 8:08









Matthew FrenchMatthew French

113




113




New contributor




Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Matthew French is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












  • $begingroup$
    I don't see what the problem is here? You start by trying the biggest pack, until there are fewer widgets left than the size of that pack. Then you move to a smaller pack, and so on, until the smallest pack. If there are some ordered widget left, after all of this, you add one smallest pack. That's it. If you can do it by hand, then you can certainly program it.
    $endgroup$
    – KIKO Software
    Apr 2 at 11:08












  • $begingroup$
    Can you confirm that the code is complete and that it functions correctly? If so, I recommend that you edit to add a summary of the testing (ideally as reproducible unit-test code). If it's not working, it isn't ready for review (see help center) and the question may be deleted.
    $endgroup$
    – Toby Speight
    Apr 2 at 11:46


















  • $begingroup$
    I don't see what the problem is here? You start by trying the biggest pack, until there are fewer widgets left than the size of that pack. Then you move to a smaller pack, and so on, until the smallest pack. If there are some ordered widget left, after all of this, you add one smallest pack. That's it. If you can do it by hand, then you can certainly program it.
    $endgroup$
    – KIKO Software
    Apr 2 at 11:08












  • $begingroup$
    Can you confirm that the code is complete and that it functions correctly? If so, I recommend that you edit to add a summary of the testing (ideally as reproducible unit-test code). If it's not working, it isn't ready for review (see help center) and the question may be deleted.
    $endgroup$
    – Toby Speight
    Apr 2 at 11:46
















$begingroup$
I don't see what the problem is here? You start by trying the biggest pack, until there are fewer widgets left than the size of that pack. Then you move to a smaller pack, and so on, until the smallest pack. If there are some ordered widget left, after all of this, you add one smallest pack. That's it. If you can do it by hand, then you can certainly program it.
$endgroup$
– KIKO Software
Apr 2 at 11:08






$begingroup$
I don't see what the problem is here? You start by trying the biggest pack, until there are fewer widgets left than the size of that pack. Then you move to a smaller pack, and so on, until the smallest pack. If there are some ordered widget left, after all of this, you add one smallest pack. That's it. If you can do it by hand, then you can certainly program it.
$endgroup$
– KIKO Software
Apr 2 at 11:08














$begingroup$
Can you confirm that the code is complete and that it functions correctly? If so, I recommend that you edit to add a summary of the testing (ideally as reproducible unit-test code). If it's not working, it isn't ready for review (see help center) and the question may be deleted.
$endgroup$
– Toby Speight
Apr 2 at 11:46




$begingroup$
Can you confirm that the code is complete and that it functions correctly? If so, I recommend that you edit to add a summary of the testing (ideally as reproducible unit-test code). If it's not working, it isn't ready for review (see help center) and the question may be deleted.
$endgroup$
– Toby Speight
Apr 2 at 11:46










2 Answers
2






active

oldest

votes


















2












$begingroup$

OK, I agree that this is a bit harder than I assumed yesterday. You basically have two opposing demands:




  1. No more widgets than necessary should be sent.

  2. The fewest packs possible should be sent.


You cannot fulfill both. So if I tried to send 1200 widgets, rule 2 says I should send a pack of 2000, however, rule 1 says I should send 2 packs: one of 1000 and one of 250. Which rule should prevail?



I chose that rule 1 should prevail in the solution below. The reason is that no customer wants more widgets than absolutely necessary.



$packSizes = [ 250,
500,
1000,
2000,
5000];

function optimizePacks($packSizes,$number)
{
rsort($packSizes);
$requiredPacks = array_fill_keys($packSizes,0);
foreach ($packSizes as $size) {
$packs = floor($number/$size);
if ($packs > 0) {
$requiredPacks[$size] = $packs;
$number -= $packs*$size;
}
}
if ($number > 0) $requiredPacks[min($packSizes)]++;
return $requiredPacks;
}

$packs = optimizePacks($packSizes,6666);

print_r($packs);


This will work for any array of pack sizes and any number of widgets. The output of this code is:




Array (
[5000] => 1
[2000] => 0
[1000] => 1
[500] => 1
[250] => 1 )




Which is one pack more than rule 2 would demand (one of 5000 and two of 1000). It would, of course, be possible to let rule 2 prevail, but I cannot fulfill both rules.






share|improve this answer











$endgroup$













  • $begingroup$
    You missed a rule Only whole packs can be sent The other 2 rules do not compete, you can send No more widgets than necessary should be sent. and The fewest packs possible should be sent For example 1200 would not be more then necessary and the 2000 unit box would be fewest packs - See the Only whole packs is the real competing rule (against, fewest packs) if that makes sense, well it makes sense to me. The more then necessary rule is actually half a rule So it can be ignored without the Only whole packs rule.
    $endgroup$
    – ArtisticPhoenix
    yesterday












  • $begingroup$
    Sending 1200 parts in a box that "can" hold 2000 is not sending more parts then necessary, it's sending the necessary parts in a bigger box. I built something like this before, I thought of the game Mancala
    $endgroup$
    – ArtisticPhoenix
    yesterday





















1












$begingroup$

Here is one using a while loop and simple subtaction:



$packSizes = [250,500,1000,2000,5000];
$number = 3000;

function optimizePacks($packSizes,$number)
{
//insure packs are in decending order
rsort($packSizes);
//create a default array
$results = array_fill_keys($packSizes, 0);

while($number > 0){
echo "---------- $number ----------n";

foreach($packSizes as $size){
if($size <= $number) break;
}
++$results[$size];
$number -= $size;
}
return $results;
}

$tests = [
1, // (1 x 250)
251, // (1 x 500)
501, // (1 x 500 and 1 x 250)
12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

];

foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


Output



---------- 1 ----------
Array
(
[5000] => 0
[2000] => 0
[1000] => 0
[500] => 0
[250] => 1
)
---------- 251 ----------
---------- 1 ----------
Array
(
[5000] => 0
[2000] => 0
[1000] => 0
[500] => 0
[250] => 2 //deviates from your example output (see below)
)
---------- 501 ----------
---------- 1 ----------
Array
(
[5000] => 0
[2000] => 0
[1000] => 0
[500] => 1
[250] => 1
)
---------- 12001 ----------
---------- 7001 ----------
---------- 2001 ----------
---------- 1 ----------
Array
(
[5000] => 2
[2000] => 1
[1000] => 0
[500] => 0
[250] => 1
)


Sandbox



These 2 examples are at odds with each other



251,    // (1 x 500)
501, // (1 x 500 and 1 x 250)


The first one you make one incomplete 500 part box



The second one you make a 500 (complete box) and an extra 250 with one part.



So the question is, why is the first one only 1 box as it should be 250 x 2 boxes. Conversely why is the second 2 boxes when it could be 1000 x 1 boxes.



So either you fit them in the smallest box that can contain them with the extra overflowing. Or you put them in complete boxes and put the remainder in the smallest box.



UPDATE



If you want the reverse I came up with this:

$packSizes = [250,500,1000,2000,5000];

function optimizePacks($packSizes,$number)
{
//insure packs are in ascending order
sort($packSizes);
//create a default array
$results = array_fill_keys($packSizes, 0);

while($number > 0){
echo "---------- $number ----------n";

foreach($packSizes as $size){
if($size >= $number) break;
}

++$results[$size];
$number -= $size;
}
return $results;
}

$tests = [
1, // (1 x 250)
251, // (1 x 500)
501, // (1 x 500 and 1 x 250)
12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

];

foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


Output



---------- 1 ----------
Array
(
[250] => 1
[500] => 0
[1000] => 0
[2000] => 0
[5000] => 0
)
---------- 251 ----------
Array
(
[250] => 0
[500] => 1
[1000] => 0
[2000] => 0
[5000] => 0
)
---------- 501 ----------
Array
(
[250] => 0
[500] => 0
[1000] => 1 //deviates from your example output
[2000] => 0
[5000] => 0
)
---------- 12001 ----------
---------- 7001 ----------
---------- 2001 ----------
Array
(
[250] => 0
[500] => 0
[1000] => 0
[2000] => 0
[5000] => 3 //deviates from your example output
)


This also points out how the last example is at odds with this way. Which is to fit the most parts in the smallest size box. This may be a bigger box but it will not overflow. For example it wont pick 5000 for 1 part.



I used a pretty nice trick with the foreach in the above code, that let me simplify it greatly.



This only works if you sort it ASC, because if we don't find a box that can hold the full number, the last iteration leaves $size at the Max value in the array (its the last one after all). Which is exactly what we want because then we subtract that from $number and repeat the process.



However if we do find a box that can contain all the parts, we simply exit (break) the foreach loop. This will be the smallest box that can fit all the parts (naturally). And we also subtract this which will leave $number at <= 0 and break the while loop which completes the function and returns the results.



Sandbox



If you really want them (the sizes, compare the 2 results in my examples) in the other order, we can either send them in that order and build the default first, or sort one way build the default then reverse the array (which should be faster then sort).



function optimizePacks($packSizes,$number)
{
//insure packs are in decending order
rsort($packSizes);
//create a default array (baking in the order)
$results = array_fill_keys($packSizes, 0);
//flip the order
$packSizes = array_reverse($packSizes);


while($number > 0){


Sandbox



Summery



Essentially you can't have both of these (or your mixed examples) without a whole lot of conditional statements that would violate using a dynamic array of sizes. You could do that with fixed sizes and special if conditions, for example. This is because your inconsistently applying your rules.



Hope it helps, I get some weird enjoyment out of figuring this stuff out... lol






share|improve this answer











$endgroup$














    Your Answer





    StackExchange.ifUsing("editor", function () {
    return StackExchange.using("mathjaxEditing", function () {
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    });
    });
    }, "mathjax-editing");

    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });






    Matthew French is a new contributor. Be nice, and check out our Code of Conduct.










    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216702%2fphp-packing-widgets-into-the-fewest-number-of-boxes-plus-minimum-order-quanti%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2












    $begingroup$

    OK, I agree that this is a bit harder than I assumed yesterday. You basically have two opposing demands:




    1. No more widgets than necessary should be sent.

    2. The fewest packs possible should be sent.


    You cannot fulfill both. So if I tried to send 1200 widgets, rule 2 says I should send a pack of 2000, however, rule 1 says I should send 2 packs: one of 1000 and one of 250. Which rule should prevail?



    I chose that rule 1 should prevail in the solution below. The reason is that no customer wants more widgets than absolutely necessary.



    $packSizes = [ 250,
    500,
    1000,
    2000,
    5000];

    function optimizePacks($packSizes,$number)
    {
    rsort($packSizes);
    $requiredPacks = array_fill_keys($packSizes,0);
    foreach ($packSizes as $size) {
    $packs = floor($number/$size);
    if ($packs > 0) {
    $requiredPacks[$size] = $packs;
    $number -= $packs*$size;
    }
    }
    if ($number > 0) $requiredPacks[min($packSizes)]++;
    return $requiredPacks;
    }

    $packs = optimizePacks($packSizes,6666);

    print_r($packs);


    This will work for any array of pack sizes and any number of widgets. The output of this code is:




    Array (
    [5000] => 1
    [2000] => 0
    [1000] => 1
    [500] => 1
    [250] => 1 )




    Which is one pack more than rule 2 would demand (one of 5000 and two of 1000). It would, of course, be possible to let rule 2 prevail, but I cannot fulfill both rules.






    share|improve this answer











    $endgroup$













    • $begingroup$
      You missed a rule Only whole packs can be sent The other 2 rules do not compete, you can send No more widgets than necessary should be sent. and The fewest packs possible should be sent For example 1200 would not be more then necessary and the 2000 unit box would be fewest packs - See the Only whole packs is the real competing rule (against, fewest packs) if that makes sense, well it makes sense to me. The more then necessary rule is actually half a rule So it can be ignored without the Only whole packs rule.
      $endgroup$
      – ArtisticPhoenix
      yesterday












    • $begingroup$
      Sending 1200 parts in a box that "can" hold 2000 is not sending more parts then necessary, it's sending the necessary parts in a bigger box. I built something like this before, I thought of the game Mancala
      $endgroup$
      – ArtisticPhoenix
      yesterday


















    2












    $begingroup$

    OK, I agree that this is a bit harder than I assumed yesterday. You basically have two opposing demands:




    1. No more widgets than necessary should be sent.

    2. The fewest packs possible should be sent.


    You cannot fulfill both. So if I tried to send 1200 widgets, rule 2 says I should send a pack of 2000, however, rule 1 says I should send 2 packs: one of 1000 and one of 250. Which rule should prevail?



    I chose that rule 1 should prevail in the solution below. The reason is that no customer wants more widgets than absolutely necessary.



    $packSizes = [ 250,
    500,
    1000,
    2000,
    5000];

    function optimizePacks($packSizes,$number)
    {
    rsort($packSizes);
    $requiredPacks = array_fill_keys($packSizes,0);
    foreach ($packSizes as $size) {
    $packs = floor($number/$size);
    if ($packs > 0) {
    $requiredPacks[$size] = $packs;
    $number -= $packs*$size;
    }
    }
    if ($number > 0) $requiredPacks[min($packSizes)]++;
    return $requiredPacks;
    }

    $packs = optimizePacks($packSizes,6666);

    print_r($packs);


    This will work for any array of pack sizes and any number of widgets. The output of this code is:




    Array (
    [5000] => 1
    [2000] => 0
    [1000] => 1
    [500] => 1
    [250] => 1 )




    Which is one pack more than rule 2 would demand (one of 5000 and two of 1000). It would, of course, be possible to let rule 2 prevail, but I cannot fulfill both rules.






    share|improve this answer











    $endgroup$













    • $begingroup$
      You missed a rule Only whole packs can be sent The other 2 rules do not compete, you can send No more widgets than necessary should be sent. and The fewest packs possible should be sent For example 1200 would not be more then necessary and the 2000 unit box would be fewest packs - See the Only whole packs is the real competing rule (against, fewest packs) if that makes sense, well it makes sense to me. The more then necessary rule is actually half a rule So it can be ignored without the Only whole packs rule.
      $endgroup$
      – ArtisticPhoenix
      yesterday












    • $begingroup$
      Sending 1200 parts in a box that "can" hold 2000 is not sending more parts then necessary, it's sending the necessary parts in a bigger box. I built something like this before, I thought of the game Mancala
      $endgroup$
      – ArtisticPhoenix
      yesterday
















    2












    2








    2





    $begingroup$

    OK, I agree that this is a bit harder than I assumed yesterday. You basically have two opposing demands:




    1. No more widgets than necessary should be sent.

    2. The fewest packs possible should be sent.


    You cannot fulfill both. So if I tried to send 1200 widgets, rule 2 says I should send a pack of 2000, however, rule 1 says I should send 2 packs: one of 1000 and one of 250. Which rule should prevail?



    I chose that rule 1 should prevail in the solution below. The reason is that no customer wants more widgets than absolutely necessary.



    $packSizes = [ 250,
    500,
    1000,
    2000,
    5000];

    function optimizePacks($packSizes,$number)
    {
    rsort($packSizes);
    $requiredPacks = array_fill_keys($packSizes,0);
    foreach ($packSizes as $size) {
    $packs = floor($number/$size);
    if ($packs > 0) {
    $requiredPacks[$size] = $packs;
    $number -= $packs*$size;
    }
    }
    if ($number > 0) $requiredPacks[min($packSizes)]++;
    return $requiredPacks;
    }

    $packs = optimizePacks($packSizes,6666);

    print_r($packs);


    This will work for any array of pack sizes and any number of widgets. The output of this code is:




    Array (
    [5000] => 1
    [2000] => 0
    [1000] => 1
    [500] => 1
    [250] => 1 )




    Which is one pack more than rule 2 would demand (one of 5000 and two of 1000). It would, of course, be possible to let rule 2 prevail, but I cannot fulfill both rules.






    share|improve this answer











    $endgroup$



    OK, I agree that this is a bit harder than I assumed yesterday. You basically have two opposing demands:




    1. No more widgets than necessary should be sent.

    2. The fewest packs possible should be sent.


    You cannot fulfill both. So if I tried to send 1200 widgets, rule 2 says I should send a pack of 2000, however, rule 1 says I should send 2 packs: one of 1000 and one of 250. Which rule should prevail?



    I chose that rule 1 should prevail in the solution below. The reason is that no customer wants more widgets than absolutely necessary.



    $packSizes = [ 250,
    500,
    1000,
    2000,
    5000];

    function optimizePacks($packSizes,$number)
    {
    rsort($packSizes);
    $requiredPacks = array_fill_keys($packSizes,0);
    foreach ($packSizes as $size) {
    $packs = floor($number/$size);
    if ($packs > 0) {
    $requiredPacks[$size] = $packs;
    $number -= $packs*$size;
    }
    }
    if ($number > 0) $requiredPacks[min($packSizes)]++;
    return $requiredPacks;
    }

    $packs = optimizePacks($packSizes,6666);

    print_r($packs);


    This will work for any array of pack sizes and any number of widgets. The output of this code is:




    Array (
    [5000] => 1
    [2000] => 0
    [1000] => 1
    [500] => 1
    [250] => 1 )




    Which is one pack more than rule 2 would demand (one of 5000 and two of 1000). It would, of course, be possible to let rule 2 prevail, but I cannot fulfill both rules.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Apr 3 at 15:33

























    answered Apr 3 at 14:56









    KIKO SoftwareKIKO Software

    1,609512




    1,609512












    • $begingroup$
      You missed a rule Only whole packs can be sent The other 2 rules do not compete, you can send No more widgets than necessary should be sent. and The fewest packs possible should be sent For example 1200 would not be more then necessary and the 2000 unit box would be fewest packs - See the Only whole packs is the real competing rule (against, fewest packs) if that makes sense, well it makes sense to me. The more then necessary rule is actually half a rule So it can be ignored without the Only whole packs rule.
      $endgroup$
      – ArtisticPhoenix
      yesterday












    • $begingroup$
      Sending 1200 parts in a box that "can" hold 2000 is not sending more parts then necessary, it's sending the necessary parts in a bigger box. I built something like this before, I thought of the game Mancala
      $endgroup$
      – ArtisticPhoenix
      yesterday




















    • $begingroup$
      You missed a rule Only whole packs can be sent The other 2 rules do not compete, you can send No more widgets than necessary should be sent. and The fewest packs possible should be sent For example 1200 would not be more then necessary and the 2000 unit box would be fewest packs - See the Only whole packs is the real competing rule (against, fewest packs) if that makes sense, well it makes sense to me. The more then necessary rule is actually half a rule So it can be ignored without the Only whole packs rule.
      $endgroup$
      – ArtisticPhoenix
      yesterday












    • $begingroup$
      Sending 1200 parts in a box that "can" hold 2000 is not sending more parts then necessary, it's sending the necessary parts in a bigger box. I built something like this before, I thought of the game Mancala
      $endgroup$
      – ArtisticPhoenix
      yesterday


















    $begingroup$
    You missed a rule Only whole packs can be sent The other 2 rules do not compete, you can send No more widgets than necessary should be sent. and The fewest packs possible should be sent For example 1200 would not be more then necessary and the 2000 unit box would be fewest packs - See the Only whole packs is the real competing rule (against, fewest packs) if that makes sense, well it makes sense to me. The more then necessary rule is actually half a rule So it can be ignored without the Only whole packs rule.
    $endgroup$
    – ArtisticPhoenix
    yesterday






    $begingroup$
    You missed a rule Only whole packs can be sent The other 2 rules do not compete, you can send No more widgets than necessary should be sent. and The fewest packs possible should be sent For example 1200 would not be more then necessary and the 2000 unit box would be fewest packs - See the Only whole packs is the real competing rule (against, fewest packs) if that makes sense, well it makes sense to me. The more then necessary rule is actually half a rule So it can be ignored without the Only whole packs rule.
    $endgroup$
    – ArtisticPhoenix
    yesterday














    $begingroup$
    Sending 1200 parts in a box that "can" hold 2000 is not sending more parts then necessary, it's sending the necessary parts in a bigger box. I built something like this before, I thought of the game Mancala
    $endgroup$
    – ArtisticPhoenix
    yesterday






    $begingroup$
    Sending 1200 parts in a box that "can" hold 2000 is not sending more parts then necessary, it's sending the necessary parts in a bigger box. I built something like this before, I thought of the game Mancala
    $endgroup$
    – ArtisticPhoenix
    yesterday















    1












    $begingroup$

    Here is one using a while loop and simple subtaction:



    $packSizes = [250,500,1000,2000,5000];
    $number = 3000;

    function optimizePacks($packSizes,$number)
    {
    //insure packs are in decending order
    rsort($packSizes);
    //create a default array
    $results = array_fill_keys($packSizes, 0);

    while($number > 0){
    echo "---------- $number ----------n";

    foreach($packSizes as $size){
    if($size <= $number) break;
    }
    ++$results[$size];
    $number -= $size;
    }
    return $results;
    }

    $tests = [
    1, // (1 x 250)
    251, // (1 x 500)
    501, // (1 x 500 and 1 x 250)
    12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

    ];

    foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


    Output



    ---------- 1 ----------
    Array
    (
    [5000] => 0
    [2000] => 0
    [1000] => 0
    [500] => 0
    [250] => 1
    )
    ---------- 251 ----------
    ---------- 1 ----------
    Array
    (
    [5000] => 0
    [2000] => 0
    [1000] => 0
    [500] => 0
    [250] => 2 //deviates from your example output (see below)
    )
    ---------- 501 ----------
    ---------- 1 ----------
    Array
    (
    [5000] => 0
    [2000] => 0
    [1000] => 0
    [500] => 1
    [250] => 1
    )
    ---------- 12001 ----------
    ---------- 7001 ----------
    ---------- 2001 ----------
    ---------- 1 ----------
    Array
    (
    [5000] => 2
    [2000] => 1
    [1000] => 0
    [500] => 0
    [250] => 1
    )


    Sandbox



    These 2 examples are at odds with each other



    251,    // (1 x 500)
    501, // (1 x 500 and 1 x 250)


    The first one you make one incomplete 500 part box



    The second one you make a 500 (complete box) and an extra 250 with one part.



    So the question is, why is the first one only 1 box as it should be 250 x 2 boxes. Conversely why is the second 2 boxes when it could be 1000 x 1 boxes.



    So either you fit them in the smallest box that can contain them with the extra overflowing. Or you put them in complete boxes and put the remainder in the smallest box.



    UPDATE



    If you want the reverse I came up with this:

    $packSizes = [250,500,1000,2000,5000];

    function optimizePacks($packSizes,$number)
    {
    //insure packs are in ascending order
    sort($packSizes);
    //create a default array
    $results = array_fill_keys($packSizes, 0);

    while($number > 0){
    echo "---------- $number ----------n";

    foreach($packSizes as $size){
    if($size >= $number) break;
    }

    ++$results[$size];
    $number -= $size;
    }
    return $results;
    }

    $tests = [
    1, // (1 x 250)
    251, // (1 x 500)
    501, // (1 x 500 and 1 x 250)
    12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

    ];

    foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


    Output



    ---------- 1 ----------
    Array
    (
    [250] => 1
    [500] => 0
    [1000] => 0
    [2000] => 0
    [5000] => 0
    )
    ---------- 251 ----------
    Array
    (
    [250] => 0
    [500] => 1
    [1000] => 0
    [2000] => 0
    [5000] => 0
    )
    ---------- 501 ----------
    Array
    (
    [250] => 0
    [500] => 0
    [1000] => 1 //deviates from your example output
    [2000] => 0
    [5000] => 0
    )
    ---------- 12001 ----------
    ---------- 7001 ----------
    ---------- 2001 ----------
    Array
    (
    [250] => 0
    [500] => 0
    [1000] => 0
    [2000] => 0
    [5000] => 3 //deviates from your example output
    )


    This also points out how the last example is at odds with this way. Which is to fit the most parts in the smallest size box. This may be a bigger box but it will not overflow. For example it wont pick 5000 for 1 part.



    I used a pretty nice trick with the foreach in the above code, that let me simplify it greatly.



    This only works if you sort it ASC, because if we don't find a box that can hold the full number, the last iteration leaves $size at the Max value in the array (its the last one after all). Which is exactly what we want because then we subtract that from $number and repeat the process.



    However if we do find a box that can contain all the parts, we simply exit (break) the foreach loop. This will be the smallest box that can fit all the parts (naturally). And we also subtract this which will leave $number at <= 0 and break the while loop which completes the function and returns the results.



    Sandbox



    If you really want them (the sizes, compare the 2 results in my examples) in the other order, we can either send them in that order and build the default first, or sort one way build the default then reverse the array (which should be faster then sort).



    function optimizePacks($packSizes,$number)
    {
    //insure packs are in decending order
    rsort($packSizes);
    //create a default array (baking in the order)
    $results = array_fill_keys($packSizes, 0);
    //flip the order
    $packSizes = array_reverse($packSizes);


    while($number > 0){


    Sandbox



    Summery



    Essentially you can't have both of these (or your mixed examples) without a whole lot of conditional statements that would violate using a dynamic array of sizes. You could do that with fixed sizes and special if conditions, for example. This is because your inconsistently applying your rules.



    Hope it helps, I get some weird enjoyment out of figuring this stuff out... lol






    share|improve this answer











    $endgroup$


















      1












      $begingroup$

      Here is one using a while loop and simple subtaction:



      $packSizes = [250,500,1000,2000,5000];
      $number = 3000;

      function optimizePacks($packSizes,$number)
      {
      //insure packs are in decending order
      rsort($packSizes);
      //create a default array
      $results = array_fill_keys($packSizes, 0);

      while($number > 0){
      echo "---------- $number ----------n";

      foreach($packSizes as $size){
      if($size <= $number) break;
      }
      ++$results[$size];
      $number -= $size;
      }
      return $results;
      }

      $tests = [
      1, // (1 x 250)
      251, // (1 x 500)
      501, // (1 x 500 and 1 x 250)
      12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

      ];

      foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


      Output



      ---------- 1 ----------
      Array
      (
      [5000] => 0
      [2000] => 0
      [1000] => 0
      [500] => 0
      [250] => 1
      )
      ---------- 251 ----------
      ---------- 1 ----------
      Array
      (
      [5000] => 0
      [2000] => 0
      [1000] => 0
      [500] => 0
      [250] => 2 //deviates from your example output (see below)
      )
      ---------- 501 ----------
      ---------- 1 ----------
      Array
      (
      [5000] => 0
      [2000] => 0
      [1000] => 0
      [500] => 1
      [250] => 1
      )
      ---------- 12001 ----------
      ---------- 7001 ----------
      ---------- 2001 ----------
      ---------- 1 ----------
      Array
      (
      [5000] => 2
      [2000] => 1
      [1000] => 0
      [500] => 0
      [250] => 1
      )


      Sandbox



      These 2 examples are at odds with each other



      251,    // (1 x 500)
      501, // (1 x 500 and 1 x 250)


      The first one you make one incomplete 500 part box



      The second one you make a 500 (complete box) and an extra 250 with one part.



      So the question is, why is the first one only 1 box as it should be 250 x 2 boxes. Conversely why is the second 2 boxes when it could be 1000 x 1 boxes.



      So either you fit them in the smallest box that can contain them with the extra overflowing. Or you put them in complete boxes and put the remainder in the smallest box.



      UPDATE



      If you want the reverse I came up with this:

      $packSizes = [250,500,1000,2000,5000];

      function optimizePacks($packSizes,$number)
      {
      //insure packs are in ascending order
      sort($packSizes);
      //create a default array
      $results = array_fill_keys($packSizes, 0);

      while($number > 0){
      echo "---------- $number ----------n";

      foreach($packSizes as $size){
      if($size >= $number) break;
      }

      ++$results[$size];
      $number -= $size;
      }
      return $results;
      }

      $tests = [
      1, // (1 x 250)
      251, // (1 x 500)
      501, // (1 x 500 and 1 x 250)
      12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

      ];

      foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


      Output



      ---------- 1 ----------
      Array
      (
      [250] => 1
      [500] => 0
      [1000] => 0
      [2000] => 0
      [5000] => 0
      )
      ---------- 251 ----------
      Array
      (
      [250] => 0
      [500] => 1
      [1000] => 0
      [2000] => 0
      [5000] => 0
      )
      ---------- 501 ----------
      Array
      (
      [250] => 0
      [500] => 0
      [1000] => 1 //deviates from your example output
      [2000] => 0
      [5000] => 0
      )
      ---------- 12001 ----------
      ---------- 7001 ----------
      ---------- 2001 ----------
      Array
      (
      [250] => 0
      [500] => 0
      [1000] => 0
      [2000] => 0
      [5000] => 3 //deviates from your example output
      )


      This also points out how the last example is at odds with this way. Which is to fit the most parts in the smallest size box. This may be a bigger box but it will not overflow. For example it wont pick 5000 for 1 part.



      I used a pretty nice trick with the foreach in the above code, that let me simplify it greatly.



      This only works if you sort it ASC, because if we don't find a box that can hold the full number, the last iteration leaves $size at the Max value in the array (its the last one after all). Which is exactly what we want because then we subtract that from $number and repeat the process.



      However if we do find a box that can contain all the parts, we simply exit (break) the foreach loop. This will be the smallest box that can fit all the parts (naturally). And we also subtract this which will leave $number at <= 0 and break the while loop which completes the function and returns the results.



      Sandbox



      If you really want them (the sizes, compare the 2 results in my examples) in the other order, we can either send them in that order and build the default first, or sort one way build the default then reverse the array (which should be faster then sort).



      function optimizePacks($packSizes,$number)
      {
      //insure packs are in decending order
      rsort($packSizes);
      //create a default array (baking in the order)
      $results = array_fill_keys($packSizes, 0);
      //flip the order
      $packSizes = array_reverse($packSizes);


      while($number > 0){


      Sandbox



      Summery



      Essentially you can't have both of these (or your mixed examples) without a whole lot of conditional statements that would violate using a dynamic array of sizes. You could do that with fixed sizes and special if conditions, for example. This is because your inconsistently applying your rules.



      Hope it helps, I get some weird enjoyment out of figuring this stuff out... lol






      share|improve this answer











      $endgroup$
















        1












        1








        1





        $begingroup$

        Here is one using a while loop and simple subtaction:



        $packSizes = [250,500,1000,2000,5000];
        $number = 3000;

        function optimizePacks($packSizes,$number)
        {
        //insure packs are in decending order
        rsort($packSizes);
        //create a default array
        $results = array_fill_keys($packSizes, 0);

        while($number > 0){
        echo "---------- $number ----------n";

        foreach($packSizes as $size){
        if($size <= $number) break;
        }
        ++$results[$size];
        $number -= $size;
        }
        return $results;
        }

        $tests = [
        1, // (1 x 250)
        251, // (1 x 500)
        501, // (1 x 500 and 1 x 250)
        12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

        ];

        foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


        Output



        ---------- 1 ----------
        Array
        (
        [5000] => 0
        [2000] => 0
        [1000] => 0
        [500] => 0
        [250] => 1
        )
        ---------- 251 ----------
        ---------- 1 ----------
        Array
        (
        [5000] => 0
        [2000] => 0
        [1000] => 0
        [500] => 0
        [250] => 2 //deviates from your example output (see below)
        )
        ---------- 501 ----------
        ---------- 1 ----------
        Array
        (
        [5000] => 0
        [2000] => 0
        [1000] => 0
        [500] => 1
        [250] => 1
        )
        ---------- 12001 ----------
        ---------- 7001 ----------
        ---------- 2001 ----------
        ---------- 1 ----------
        Array
        (
        [5000] => 2
        [2000] => 1
        [1000] => 0
        [500] => 0
        [250] => 1
        )


        Sandbox



        These 2 examples are at odds with each other



        251,    // (1 x 500)
        501, // (1 x 500 and 1 x 250)


        The first one you make one incomplete 500 part box



        The second one you make a 500 (complete box) and an extra 250 with one part.



        So the question is, why is the first one only 1 box as it should be 250 x 2 boxes. Conversely why is the second 2 boxes when it could be 1000 x 1 boxes.



        So either you fit them in the smallest box that can contain them with the extra overflowing. Or you put them in complete boxes and put the remainder in the smallest box.



        UPDATE



        If you want the reverse I came up with this:

        $packSizes = [250,500,1000,2000,5000];

        function optimizePacks($packSizes,$number)
        {
        //insure packs are in ascending order
        sort($packSizes);
        //create a default array
        $results = array_fill_keys($packSizes, 0);

        while($number > 0){
        echo "---------- $number ----------n";

        foreach($packSizes as $size){
        if($size >= $number) break;
        }

        ++$results[$size];
        $number -= $size;
        }
        return $results;
        }

        $tests = [
        1, // (1 x 250)
        251, // (1 x 500)
        501, // (1 x 500 and 1 x 250)
        12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

        ];

        foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


        Output



        ---------- 1 ----------
        Array
        (
        [250] => 1
        [500] => 0
        [1000] => 0
        [2000] => 0
        [5000] => 0
        )
        ---------- 251 ----------
        Array
        (
        [250] => 0
        [500] => 1
        [1000] => 0
        [2000] => 0
        [5000] => 0
        )
        ---------- 501 ----------
        Array
        (
        [250] => 0
        [500] => 0
        [1000] => 1 //deviates from your example output
        [2000] => 0
        [5000] => 0
        )
        ---------- 12001 ----------
        ---------- 7001 ----------
        ---------- 2001 ----------
        Array
        (
        [250] => 0
        [500] => 0
        [1000] => 0
        [2000] => 0
        [5000] => 3 //deviates from your example output
        )


        This also points out how the last example is at odds with this way. Which is to fit the most parts in the smallest size box. This may be a bigger box but it will not overflow. For example it wont pick 5000 for 1 part.



        I used a pretty nice trick with the foreach in the above code, that let me simplify it greatly.



        This only works if you sort it ASC, because if we don't find a box that can hold the full number, the last iteration leaves $size at the Max value in the array (its the last one after all). Which is exactly what we want because then we subtract that from $number and repeat the process.



        However if we do find a box that can contain all the parts, we simply exit (break) the foreach loop. This will be the smallest box that can fit all the parts (naturally). And we also subtract this which will leave $number at <= 0 and break the while loop which completes the function and returns the results.



        Sandbox



        If you really want them (the sizes, compare the 2 results in my examples) in the other order, we can either send them in that order and build the default first, or sort one way build the default then reverse the array (which should be faster then sort).



        function optimizePacks($packSizes,$number)
        {
        //insure packs are in decending order
        rsort($packSizes);
        //create a default array (baking in the order)
        $results = array_fill_keys($packSizes, 0);
        //flip the order
        $packSizes = array_reverse($packSizes);


        while($number > 0){


        Sandbox



        Summery



        Essentially you can't have both of these (or your mixed examples) without a whole lot of conditional statements that would violate using a dynamic array of sizes. You could do that with fixed sizes and special if conditions, for example. This is because your inconsistently applying your rules.



        Hope it helps, I get some weird enjoyment out of figuring this stuff out... lol






        share|improve this answer











        $endgroup$



        Here is one using a while loop and simple subtaction:



        $packSizes = [250,500,1000,2000,5000];
        $number = 3000;

        function optimizePacks($packSizes,$number)
        {
        //insure packs are in decending order
        rsort($packSizes);
        //create a default array
        $results = array_fill_keys($packSizes, 0);

        while($number > 0){
        echo "---------- $number ----------n";

        foreach($packSizes as $size){
        if($size <= $number) break;
        }
        ++$results[$size];
        $number -= $size;
        }
        return $results;
        }

        $tests = [
        1, // (1 x 250)
        251, // (1 x 500)
        501, // (1 x 500 and 1 x 250)
        12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

        ];

        foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


        Output



        ---------- 1 ----------
        Array
        (
        [5000] => 0
        [2000] => 0
        [1000] => 0
        [500] => 0
        [250] => 1
        )
        ---------- 251 ----------
        ---------- 1 ----------
        Array
        (
        [5000] => 0
        [2000] => 0
        [1000] => 0
        [500] => 0
        [250] => 2 //deviates from your example output (see below)
        )
        ---------- 501 ----------
        ---------- 1 ----------
        Array
        (
        [5000] => 0
        [2000] => 0
        [1000] => 0
        [500] => 1
        [250] => 1
        )
        ---------- 12001 ----------
        ---------- 7001 ----------
        ---------- 2001 ----------
        ---------- 1 ----------
        Array
        (
        [5000] => 2
        [2000] => 1
        [1000] => 0
        [500] => 0
        [250] => 1
        )


        Sandbox



        These 2 examples are at odds with each other



        251,    // (1 x 500)
        501, // (1 x 500 and 1 x 250)


        The first one you make one incomplete 500 part box



        The second one you make a 500 (complete box) and an extra 250 with one part.



        So the question is, why is the first one only 1 box as it should be 250 x 2 boxes. Conversely why is the second 2 boxes when it could be 1000 x 1 boxes.



        So either you fit them in the smallest box that can contain them with the extra overflowing. Or you put them in complete boxes and put the remainder in the smallest box.



        UPDATE



        If you want the reverse I came up with this:

        $packSizes = [250,500,1000,2000,5000];

        function optimizePacks($packSizes,$number)
        {
        //insure packs are in ascending order
        sort($packSizes);
        //create a default array
        $results = array_fill_keys($packSizes, 0);

        while($number > 0){
        echo "---------- $number ----------n";

        foreach($packSizes as $size){
        if($size >= $number) break;
        }

        ++$results[$size];
        $number -= $size;
        }
        return $results;
        }

        $tests = [
        1, // (1 x 250)
        251, // (1 x 500)
        501, // (1 x 500 and 1 x 250)
        12001 // (2 x 5000 and 1 x 2000 and 1 x 250)

        ];

        foreach($tests as $test) print_r(optimizePacks($packSizes,$test));


        Output



        ---------- 1 ----------
        Array
        (
        [250] => 1
        [500] => 0
        [1000] => 0
        [2000] => 0
        [5000] => 0
        )
        ---------- 251 ----------
        Array
        (
        [250] => 0
        [500] => 1
        [1000] => 0
        [2000] => 0
        [5000] => 0
        )
        ---------- 501 ----------
        Array
        (
        [250] => 0
        [500] => 0
        [1000] => 1 //deviates from your example output
        [2000] => 0
        [5000] => 0
        )
        ---------- 12001 ----------
        ---------- 7001 ----------
        ---------- 2001 ----------
        Array
        (
        [250] => 0
        [500] => 0
        [1000] => 0
        [2000] => 0
        [5000] => 3 //deviates from your example output
        )


        This also points out how the last example is at odds with this way. Which is to fit the most parts in the smallest size box. This may be a bigger box but it will not overflow. For example it wont pick 5000 for 1 part.



        I used a pretty nice trick with the foreach in the above code, that let me simplify it greatly.



        This only works if you sort it ASC, because if we don't find a box that can hold the full number, the last iteration leaves $size at the Max value in the array (its the last one after all). Which is exactly what we want because then we subtract that from $number and repeat the process.



        However if we do find a box that can contain all the parts, we simply exit (break) the foreach loop. This will be the smallest box that can fit all the parts (naturally). And we also subtract this which will leave $number at <= 0 and break the while loop which completes the function and returns the results.



        Sandbox



        If you really want them (the sizes, compare the 2 results in my examples) in the other order, we can either send them in that order and build the default first, or sort one way build the default then reverse the array (which should be faster then sort).



        function optimizePacks($packSizes,$number)
        {
        //insure packs are in decending order
        rsort($packSizes);
        //create a default array (baking in the order)
        $results = array_fill_keys($packSizes, 0);
        //flip the order
        $packSizes = array_reverse($packSizes);


        while($number > 0){


        Sandbox



        Summery



        Essentially you can't have both of these (or your mixed examples) without a whole lot of conditional statements that would violate using a dynamic array of sizes. You could do that with fixed sizes and special if conditions, for example. This is because your inconsistently applying your rules.



        Hope it helps, I get some weird enjoyment out of figuring this stuff out... lol







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited yesterday

























        answered yesterday









        ArtisticPhoenixArtisticPhoenix

        45127




        45127






















            Matthew French is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded


















            Matthew French is a new contributor. Be nice, and check out our Code of Conduct.













            Matthew French is a new contributor. Be nice, and check out our Code of Conduct.












            Matthew French is a new contributor. Be nice, and check out our Code of Conduct.
















            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216702%2fphp-packing-widgets-into-the-fewest-number-of-boxes-plus-minimum-order-quanti%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            is 'sed' thread safeWhat should someone know about using Python scripts in the shell?Nexenta bash script uses...

            How do i solve the “ No module named 'mlxtend' ” issue on Jupyter?

            Pilgersdorf Inhaltsverzeichnis Geografie | Geschichte | Bevölkerungsentwicklung | Politik | Kultur...