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 reduce5
($a[101]
) to0
(new $a[101]
) then7
becomes the carried value and the next value in$a
will be the new focus.100
($a[109]
) is first reduce by7
(carried
) and becomes93
(new $a[109
).93
(new [109]
) is then reduced again by15
($b[LOG]
) and becomes78
(new [109]
).78
(new [109]
) is then reduced again by100
($b[DEV]
) flooring the value to0
, making a new carried value of22
, and moving focus to$a[220]
.50
($a[220]
) is reduced by22
(carried
) making28
(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,
)