Merge Two Arrays to Have an Integer Value be an near equal as possible

37
March 14, 2019, at 7:40 PM

Application to Distribute Stock between Warehouses

I have two arrays,

One has list of Warehouses along with the Current Quantity: (This can be Dynamic with one or more locations)

[
    ['location_name' => 'Toronto',    'current_qty'   => 3],
    ['location_name' => 'Mississauga','current_qty'   => 7],
    ['location_name' => 'London',     'current_qty'   => 5],
]

The Other array has the Amount of Stock that would be Comming in:

[
     'qty' => 5
]

And want to distribute the Qty among the locations so that the current qty of each of the locations would be near equal to each other. So want to return an array with the number that needs to be added to each location. Like: Here , of the 5, 3 went to Toronto and 2 to London. So it can be seen then after the nearest equalization, rest of the distribution can be done randomly.

[
    ['location_name' => 'Toronto',    'add_qty'   => 3],
    ['location_name' => 'Mississauga','add_qty'   => 0],
    ['location_name' => 'London',     'add_qty'   => 2],
]

And Just cannot figure out the logic of this algorithm. Would really appreciate any pointers. Many Thanks.

Answer 1

I would do it like this, not really sure about any performance issues. I don't know how big your data set is.

$locations = [
    ['location_name' => 'Toronto', 'current_qty' => 3, 'add_qty' => 0],
    ['location_name' => 'Mississauga', 'current_qty' => 7, 'add_qty' => 0],
    ['location_name' => 'London', 'current_qty' => 5, 'add_qty' => 0],
];
$supplies = 5;
// This function sorts locations, by comparing the sum of the current quantity and the quantity the location will get.
$locationsByQuantityAscending = function ($locationA, $locationB) {
    return ($locationA['current_qty'] + $locationA['add_qty']) - ($locationB['current_qty'] + $locationB['add_qty']);
};
// Sort the locations, getting the ones with the lowest quantity first.
usort($locations, $locationsByQuantityAscending);
// Keep dividing, until we're out of supplies
while ($supplies > 0) {
    $locations[0]['add_qty']++; // Add one to the location with the lowest supplies
    $supplies--; // Decrease the supplies by one
    usort($locations, $locationsByQuantityAscending); // Sort the locations again.
}
print_r($locations);

At the end, this will output:

Array
(
    [0] => Array
        (
            [location_name] => Toronto
            [current_qty] => 3
            [add_qty] => 3
        )
    [1] => Array
        (
            [location_name] => London
            [current_qty] => 5
            [add_qty] => 2
        )
    [2] => Array
        (
            [location_name] => Mississauga
            [current_qty] => 7
            [add_qty] => 0
        )
)

If you really need to be performant, you could also just sort the locations once by their current quantity. Then keep adding to the first location, until its stock will be higher than the second location. Then, until the quantity at the second location is higher than the third location, add one to the first and second location, etc.

I think this will be more performant, since you don't have to sort all your locations X times (X being the number of supplies to divide). I'll leave that implementation to you.

Hint: have a look at recursive functions

Answer 2

If performance is critical, and the input data is usually bigger then shown here (e.g. a lot more locations or a lot more quantity to distribute). You might want to consider using SplMinHeap:

For example:

<?php
$helper = new class extends SplMinHeap
{
    public function compare($a, $b): int
    {
        return ($b['current_qty'] + $b['add_qty']) <=> ($a['current_qty'] + $a['add_qty']);
    }
};
$locations = [
    ['location_name' => 'Toronto',     'current_qty' => 3, 'add_qty' => 0],
    ['location_name' => 'Mississauga', 'current_qty' => 7, 'add_qty' => 0],
    ['location_name' => 'London',      'current_qty' => 5, 'add_qty' => 0],
];
foreach ($locations as $entry) {
    $helper->insert($entry);
}
$qty = 10000;
while ($qty-- > 0) {
    $min = $helper->extract();
    $min['add_qty']++;
    $helper->insert($min);
}
print_r(iterator_to_array($helper));

https://3v4l.org/nDOY8

READ ALSO
I have 3 TLD .com .es .ru And I have a question

I have 3 TLD .com .es .ru And I have a question

I have a webpage translated into 3 languages, my question isI would like when you enter with

59
Adding postfix to WooCommerce product variation gets overwritten

Adding postfix to WooCommerce product variation gets overwritten

Im beginning to expect that there is some "update function" built into WooCommerce that only lets me rename variations post_title for a little whileAnd then it gets set back to what the hooks / WooCommerce has decided?

50
Is it possible to check when cookie file was created?

Is it possible to check when cookie file was created?

Is it possible to check when the cookie file was created using a web based language like PHP or JS? Would this be useful in determining if a cookie has been copied from the original device it was set on to a new device?

52
Must I use Stripe&#39;s payment gateway with Laravel cashier? [on hold]

Must I use Stripe's payment gateway with Laravel cashier? [on hold]

I'm asking this because I'm currently building a subscription based web app and Stripe isn't available in my resident countryI have read Laravel Cashier documentation and they only talk about using Stripe and Braintree

64