skip to Main Content

So im try to accomplish is split items evenly through groups with a max on each group, so far I have this funtion, basicly the array count is the number of GROUPS it needs to split the ITEMS and the array values are the max value for each group:

public static function splitItems($groups, $items){
    $n = count($groups);
    $res = array_fill(0, $n, 0);

    while($items >= $groups[0]){
        for($i=$n-1;$i>=0;$i--){
            if($items >= $groups[$i])
            {
                $res[$i]++;
                $items -= $groups[$i];
            }
        }
    }

    if($items > 0){
        $res[0]++;
    }
    return $res;
}

When I run the function like this splitItems([5,5],10); the result is correct:

Array
(
    [0] => 5
    [1] => 5
)

Now the only missing part is to take in account the VALUE of array as max value, what i’m looking for are this results:

Input:

splitItems([14,2],10);
splitItems([6,8,2],14);

Output:

Array
(
    [0] => 8
    [1] => 2
)
Array
(
    [0] => 6
    [1] => 6
    [2] => 2
)

2

Answers


  1. This should work:

    function splitItems($groups, $items)
    {
        $n = count($groups);
        $res = array_fill(0, $n, 0);
        $groupsFilled = array_fill(0, $n, 0);;
    
        while ($items > 0 && count(array_keys($groupsFilled, 1)) < count($groupsFilled))
        {
            for ($i = $n-1; $i >= 0; $i--)
            {
                if ($res[$i] < $groups[$i])
                {
                    if ($items > 0) {
                        $res[$i]++;
                        $items--;
                    }
                }
                else $groupsFilled[$i] = 1;
            }
        }
    
        return $res;
    }
    
    print_r(splitItems([14,2],10));
    print_r(splitItems([6,8,2],14));
    print_r(splitItems([6,4,2],14)); //not enough space for all the items!
    

    Outputs:

    Array
    (
        [0] => 8
        [1] => 2
    )
    Array
    (
        [0] => 6
        [1] => 6
        [2] => 2
    )
    Array
    (
        [0] => 6
        [1] => 4
        [2] => 2
    )
    

    Key points:

    • The code loops until there are no more items left to distribute (in most cases, but see the last bullet point below).
    • As per your original logic it will put an item the last group first, and then work backwards to the first one. It distributes one item to each group, then goes round again until there’s nothing left.
    • It checks to ensure the group is not full before putting an item into it.
    • If you specify less total space in the groups than there are items, it will just fill the groups until there is no space left in any of them – that’s what the second condition in the while loop is doing. (What it doesn’t do is tell you how many items couldn’t be put into a group – but you could alter that if you wanted to.)

    Live demo: https://3v4l.org/R8BOg

    Login or Signup to reply.
    • To target smaller limits first, call asort() to order your elements ascending and preserve the original indexes.
    • Then loop over the elements and update their value to be the lesser amount of their original value and the amount remaining in the total.
    • Then reduce the total by the amount applied to the element and repeat.
    • Before returning the updated elements, return them to their original order, if it matters.

    This effectively fills the smaller capacities before larger capacities and never overfills. Demo

    function splitItems(array $limits, int $total): array {
        asort($limits);
        foreach ($limits as &$limit) {
            $limit = min($limit, $total);
            $total -= $limit;
        }
        ksort($limits);
        return $limits;
    }
        
    var_export(splitItems([14, 2], 10));
    echo "n---n";
    var_export(splitItems([6, 8, 2], 14));
    echo "n---n";
    var_export(splitItems([6, 4, 2], 14));
    echo "n---n";
    var_export(splitItems([7, 7, 1], 4));
    echo "n---n";
    var_export(splitItems([1, 1], 10));
    echo "n---n";
    var_export(splitItems([2,1,3],4));
    

    Output:

    array (
      0 => 8,
      1 => 2,
    )
    ---
    array (
      0 => 6,
      1 => 6,
      2 => 2,
    )
    ---
    array (
      0 => 6,
      1 => 4,
      2 => 2,
    )
    ---
    array (
      0 => 3,
      1 => 0,
      2 => 1,
    )
    ---
    array (
      0 => 1,
      1 => 1,
    )
    ---
    array (
      0 => 2,
      1 => 1,
      2 => 1,
    )
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search