Home > database >  PHP consecutive subtraction two arrays
PHP consecutive subtraction two arrays

Time:10-21

I have 2 arrays like this

a = Array([101] => 5,[109] =>100,[220] => 50,[231] => 45,[245] => 90)
b = Array(['PRO'] => 12,['LOG'] => 15,['DEV'] => 100)

I want to consecutive subtract 2 array and result like this

c = Array([101] => 0,[109] => 0, [220] => 28, [231] => 45,  [245] => 90)

Explain: I assumed used foreach to get value of a and b

1st: 5-12=0(move 7 to next time) <=> c[101] => 0;
2nd: 100-7 = 93 (7 at 1st)
3rd : 93-15 = 78
4th: 78-100 = 0 (move 22 to 5th time) <=> c[109] => 0
5th: 50-22 = 28 <=> c[220] => 28

But I don't know how to express in PHP

CodePudding user response:

The following should work:

$rest = 0;
foreach ($a as &$value) {
    if ($value < $rest) {
        $rest -= $value;
        $value = 0;
        continue;
    } else {
        $value -= $rest;
        $rest = 0;
    }

    while ($value > 0 && key($b) !== null) {
        if ($value < current($b)) {
            $rest = current($b) - $value;
            $value = 0;
        } else {
            $value -= current($b);
            $rest = 0;
        }
    
        next($b);
    }
}

Basically, this loops over the first array and in each loop:

  • it first checks whether there was a rest value from the previous iteration, and lowers the value accordingly
  • next, it'll loop over the second array from where it left off the previous iteration of the outer loop and lower the value until it reaches 0 or when the second array is 'used up'.

A working example can be found on 3v4l.

CodePudding user response:

I'll try to rephrase your requirements, because I had to read your question about 10 times before I understood what you needed.

You want to reduce the values in $a (using subtraction) by consuming the values in $b in the order by which the associative elements occur. When a value in $b is large enough to reduce the value in $a to zero or lower, you want to set the $a value to zero and carry the remaining value (difference) to the subtraction of the next value in $a. This carried value must be consumed by one or more values in $a until it is depleted. When a carried value is depleted, then the next occurring value in $b should be used to reduce the current value in $a.

  • 12($b[PRO]) is used to reduce 5($a[101]) to 0(new $a[101]) then 7 becomes the carried value and the next value in $a will be the new focus.
  • 100($a[109]) is first reduce by 7(carried) and becomes 93(new $a[109).
  • 93(new [109]) is then reduced again by 15($b[LOG]) and becomes 78(new [109]).
  • 78(new [109]) is then reduced again by 100($b[DEV]) flooring the value to 0, making a new carried value of 22, and moving focus to $a[220].
  • 50($a[220]) is reduced by 22(carried) making 28(new $a[220]).
  • At this point, the carried value is depleted AND there are no more values in $b to reduce $a values by.
  • $a[231] and $a[245] remain unchanged because there are no remaining values to subtract with.

My snippet uses text book arithmetic jargon: minuend - suprahend = difference.
The $difference is what is carried.
array_shift() is appropriate because it consumes the values in $b as they are accessed.

Code: (Demo)

$a = [
    101 => 5,
    109 => 100,
    220 => 50,
    231 => 45,
    245 => 90
];
$b = [
    'PRO' => 12,
    'LOG' => 15,
    'DEV' => 100
];

$difference = 0;
foreach ($a as &$minuend) {
    while ($minuend && ($b || $difference < 0)) {
        $suprahend = $difference < 0 ? -$difference : array_shift($b);
        $difference = $minuend - $suprahend;
        $minuend = max(0, $difference);
    }
}
var_export($a);

Output:

array (
  101 => 0,
  109 => 0,
  220 => 28,
  231 => 45,
  245 => 90,
)
  • Related