Continues Deduction using php - php

Please don't judge I just need help with this.
I have this array values from the database
# amount monthly interest rate
[0] 10,000 500 10%
[1] 400,000 12,000 5%
I want to have a recursive deduction of these arrays until data is zero, and then if the first amount of the array is zero(0) the deduction will add to the next data, until all amount will be zero (0).
Sample Calculation and my code
$data = json_decode($debtsData, true);
$continue = true;
while($continue) {
$continue = max(array_column($data, 'amount')) > 0;
for($i=0; $i<count($data); ++$i) {
$totalInterest = $data[$i]['interest_rate'] / 100;
$periods = 12;
$monthly = $data[$i]['monthly'];
$_new_balance = !isset($data[$i]['done']) ? max($data[$i]['amount'], 0) : '';
$interestPayment = ($totalInterest / $periods ) * $_new_balance;
if($data[$i]['amount'] <= 0 && !isset($data[$i]['done'])) {
$data[$i]['done'] = true;
if(isset($data[$i+1])) {
$data[$i+1]['monthly'] += $data[$i]['monthly'];
}
}
echo !isset($data[$i]['done']) ? '$'.number_format(max($data[$i]['amount'], 0),2) : '';
echo !isset($data[$i]['done']) ? '$'.number_format($data[$i]['monthly'],2) : '';
echo !isset($data[$i]['done']) ? '$'.number_format($interestPayment,2).' ' : '';
$data[$i]['amount'] -= $data[$i]['monthly'] - $interestPayment ;
}
}
My Output is Below
[0] [1]
Beginning - Monthly - Interest Beginning - Monthly - Interest
10,000 - 500 - 83.33 400,000 - 12,000 - 1,666.67
9,583.33 - 500 - 79.86 389,666.67 - 12,000 - 1,623.61
9,163.19 - 500 - 76.36 379,290.28 - 12,000 - 1,580.38
8,739.55 - 500 - 72.83 368,870.65 - 12,000 - 1,536.96
... ... ... ... ... ...
480.78 - 500 - 4.00 162,438.96 - 12,500 - 676.83
0 0 0 0 150,615.79 - 12,500 - 627.56
0 0 0 0 138,743.35 - 12,500 - 578.10
... ... ... ... ... ...
0 0 0 0 0 0 0
What I was needed is that if the first data array has a remaining monthly (e.g above is 500) and it only deducted from the amount 484.78 the remaining should be deducted as well on the second data of the array. And I also confused on how to do it if the first array is much bigger than the second data. If it is vice versa and the second array is already zero(0) the monthly should be added on the first data of the array.

Related

Distributing x amount of gold coins to n number of thieves

Suppose if there are 10 thieves and 100 gold coins to be distributed and the distribution pattern goes like this:
Thief 1 gets 1 coin.
Thief 2 gets 2 coins.
Thief 3 gets 3 coins.... and so on upto 10.
When all the thief have received the coins then the sum of total coins will be (1+2+3+... = 55 coins). Now the coins left are 45. Now, how can I start redistribution from thief one but with the last incremented value instead of starting from 1 coin again? Like 1st thief in 2nd round should get 11 coins instead of 1 and this should continue until all the coins are distributed and coin left is 0. If the last thief has to get 7 coins but the coin available is 3 then he should get 3 coins and the distribution should be over.
I tried this...
$thieves = 10;
$goldCoins = 100;
$thiefArr = range(1, $thieves);
$assgnCoins = 0;
foreach($thiefArr as $key => $value){
for($i=1; $i<=$goldCoins; $i++){
$assgnCoins = $value; // This assigns first round of coins but how to redistribute it again I have no idea.
}
echo "Thief ".$value." will have ".$assgnCoins." gold coins. <br><br>";
}
I'm not really sure if I understood your problem correctly but here's my take, hope this helps:
<?php
$numt = 10; //Total number of thieves
$totalCoins = 100; //Total coins to redistribute
$data = []; //Data array (will contains the index, which is the "thief" number, and the value of a specific index is the total amount of coins for that specific thief
//Loop init: $coins is the amount of coins given to a thief in a specific distribution round
//Loop condition: We loop until there are still coins to redistribute
//Loop statement: We add 1 coin to each redistribution round
// (I start from 0 and use $coins + 1 because I do modulus on $numt ($coins % $numt) which will give me a number from 0 to $numt - 1 (Hint/fact: array indexes start from 0 and not 1)
for ($coins = 0; $totalCoins > 0; $coins++)
{
//This will always give me a number between 0 and $numt - 1 (so that we know which thief's turn is)
//(If this is not clear, you can print out $coins and $thiefIndex then you'll see/understand why I do this)
$thiefIndex = ($coins % $numt);
//Because we did not initialize $data values, we check if this specific thief's coins amount has been initialized
if (!isset($data[$thiefIndex]))
{
$data[$thiefIndex] = 0; //Every thief starts with 0 coins
}
//Because we started from 0, we need to add 1 (this is the amount of coins that this thief ($thiefIndex) will get in this redistribution round
$coinsToGive = ($coins + 1);
//If there's not enough coins left, we just give the total coins remaining
if ($totalCoins < $coinsToGive)
{
$coinsToGive = $totalCoins;
}
//Here we sum up all coins that a thief receives in a specific redistribution round
$data[$thiefIndex] += $coinsToGive;
//We need to subtract the given coins to the total conins that we redistribute (this makes the loop break when it reaches 0 (see the loop condition part)
$totalCoins -= $coinsToGive;
}
//Use data/print in your case
foreach ($data as $idx => $tot)
{
echo "Thief ".($idx + 1)." will have ".$tot." gold coins. <br />";
}
EDIT: I think you edited the question while I was writing my answer. Anyways, if you want to see how much coins every thief is getting on every redistribution round, you can add an echo in the first loop (at the end).
If you're new to programming, you may not know what += or -= means:
$foo += $bar;
Is the same as:
$foo = $foo + $bar;
This can be applied to every arithmetical operator like +, -, *, / (and even other signs like &= and |=, etc... but those will be bit-wise operations)
Information about operators can be found online on the PHP website.
<?php
$thieves = range(1, 10);
$availableCoins = 100;
$assignCoins = 0;
while($availableCoins > 0) {
foreach($thieves as $thief) {
// increase the coins to assign
$assignCoins++;
// check if assign coins are greater than the availableCoins
if ($assignCoins > $availableCoins) {
$assignCoins = $availableCoins;
}
echo "Thief ".$thief." will have ".$assignCoins." gold coins. <br><br>";
// substract assignedCoins from availableCoins
$availableCoins -= $assignCoins;
// break the loop if no coins left
if ($availableCoins <= 0) {
break;
}
}
}
I have now edited the answer of #julian S to give the result that the homework should give:
I also have added some more HTMl input to demonstrate the structure of the array the running operations and the resulting array in readable form.
In short:
The range was wrong here.
Because it will fill an array with 1,2,3,4,5,6,7,8,9, that already is a numerical array so member 1 has a value 1 ?? Useless. NO!
So we crate an array of the 10thives weach with teh initial value = - because teh thieves have = money initially.
We print this array and add pre so that it looks a little better :-)
Then we have two loops - the outer while loop that has the function to look if there is still money left. if there is still moey left then make another round.
That was the logic missing to the original poster as he did understand that he needed a loop for the 10 thieves.
Then there is the INNER LOOP
just count from 1 to the number of thieves. So each thief will get its share.
$a += $b is the short form of $a=$a+$b
Add the currentcoins to the current arrray member
Add a break to leave the for loop if the monex is gone before you are at the end of the 10 thieves.
At the end just print the array with the wealth of the thieves.
0-9 as arrays start with 0.
<?php
$thieves = 10;
$availableCoins = 100;
$assignCoins = 0;
$array_thieves= array_fill(0,10,0);
echo "<h2>Initial array with wealth of each thief</h2> ";
echo "<pre>";
print_r($array_thieves)."<br>";
echo"</pre>";
while($availableCoins > 0) { //inerate as long as there are coins - outer loop
for($i=0; $i<$thieves; $i++) { //execute loop once per thieve so 10 x per round -inner loop
// increase the coins to assign
$assignCoins++; //we have started with 0 and each time we add 1
// check if assign coins are greater than the availableCoins
//if the number of available coins is smaller then just assign all available coins
if ($assignCoins > $availableCoins) {
$assignCoins = $availableCoins;
}
$array_thieves[$i] += $assignCoins; //add the coins to the thied (= array member) with the current number $i [0-9]
echo "Thief ". $i ." gets now additional ".$assignCoins." gold coins. He has now a total of: ". $array_thieves[$i] ." <br>";
// substract assignedCoins from availableCoins
$availableCoins -= $assignCoins;
// break the FOR loop if no coins left - otherwise the inner loop will continue
if ($availableCoins <= 0) {
break;
}
}
}
echo"<h2>Resulting array with all thieves and their wealth</h2>";
echo"<pre>";
print_r($array_thieves);
echo"</pre>";

How to check if a number falls in a given range

I have a variable $user_id (number value)
Want to check if $user_id falls in between the range of 1 - 1000 or 1001 - 2000 or 2001 - 3000 .... 99001 - 100000
Is there a way to do this without writing 100 switch or if statements in PHP?
When it finds the match, execute a code.
I know while and for loops are required for this. But not able to code it properly.
This the simplest way:
$check = 0;
$nextCheck = $check+1001;
while ($check < 100001) {
If ($user_id > $check && $user_id < $nextCheck) {
// Code ...
break;
} else {
$check+=1000;
$nextCheck+=1000;
}
}
You can just divide the number by 1000 since you have a 1000 interval range in a consecutive way.
The quotient * 1000 + 1 is your start value for the interval with an exceptional corner case of a number divisible by 1000, which would just be the border end for an interval.
<?php
$tests = [1,999,1000,50001,100000,2999];
foreach($tests as $test_case){
$quotient = intval($test_case / 1000);
if($test_case % 1000 === 0){
$start = $test_case - 1000 + 1;
echo "$test_case : Range: ($start - $test_case)",PHP_EOL;
}else{
$start = $quotient * 1000 + 1;
$end = ($quotient + 1) * 1000;
echo "$test_case : Range: ($start - $end)",PHP_EOL;
}
}
Output:
1 : Range: (1 - 1000)
999 : Range: (1 - 1000)
1000 : Range: (1 - 1000)
50001 : Range: (50001 - 51000)
100000 : Range: (99001 - 100000)
2999 : Range: (2001 - 3000)
Demo: https://3v4l.org/apbqV
Do not generate an array. Do not use a loop. Use math to determine the upper limit of the range, then subtract 999 from that number -- done.
*my snippet assumes we are only dealing with positive values between 1 and 100000.
Code: (Demo)
$tests = [1, 999, 1000, 50001, 100000, 2999];
foreach ($tests as $test) {
$upper = intval(($test - 1) / 1000) * 1000 + 1000;
echo "$test is between " . ($upper - 999) . " and $upper\n";
}
Output:
1 is between 1 and 1000
999 is between 1 and 1000
1000 is between 1 and 1000
50001 is between 50001 and 51000
100000 is between 99001 and 100000
2999 is between 2001 and 3000
Formula Breakdown:
intval( #3) remove decimals from difference
($test - 1) #1) subtract one
/ 1000 #2) divide by 1000
)
* 1000 #4) multiply integer by 1000
+ 1000 #5) add 1000

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

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. However, I'm ideally looking for a scalable, object oriented approach to solving this problem.
Here's what I've come up with so far:
<?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);
OK, I agree that this is a bit harder than I assumed yesterday. You basically have two opposing demands:
No more widgets than necessary should be sent.
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.

How to reduce the total after every iteration

I have a $paymentsTotal variable which is the sum of all payments. I then want to loop through all outstanding amounts and reduce the $paymentsTotal variable for each outstanding amount.
eg:
TotalPayments = 900 - 200
700 - 300
400 - 100
300 - 300
Stop 0
And as long as the $paymentsTotal is greater than the outstanding amount, it should return true.
I tried this:
foreach ($invoices as $invoice) {
if($paymentTotal >= $paymentTotal -= $invoice->amount) {
echo $invoice->amount . ' - PAID <br>';
}
}
but it echos out each result no matter what.
Try something like...
$paymentTotal = 0; // whatever this is before iteration
foreach($invoices as $invoice) {
if ($invoice->amount > $paymentTotal) {
$paymentTotal -= $invoice->amount; // assuming you have a field for the paid amount
$invoice->amount = $paymentTotal; // new invoice amount
echo "{$invoice->amount} - PAID <br>";
}
}

Calculate average percentage difference in a php array

Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 3
[6] => 1
)
I was wondering how one would go about working out the average percentage difference between the current value in an array and the next value. If the next value were a larger one, it would perform like so. (ie keys [0]-[1] 1/2 * 100 = 50). If it were a smaller value it would perform like so. (ie keys [4]-[5] = 3/5 * 100 = -60).
The following will represent what I am aiming to do with these percentage calculations.
1/2 * 100
2/3 * 100
3/4 * 100
4/5 * 100
3/5 * 100 (negative)
1/3 * 100 (negative)
Total : total/count
This will iterate through the list and then work out the average from the count. I have looked into splitting arrays but don't see how else I could do this.
$count = count($num);
foreach ($num as $value) {
array_chunk($num, 1);
if($value<$value){
$total1 = $total1 + ($value/$value)*100;
}
if($value>$value){
$total2 = $total2 + ($value/$value)*100;
}
}
$average = (($total1-$total2)/$count);
print($average);
I understand the above code is incorrect, but I hope it reveals where I am getting at with this.
Any help would be greatly appreciated.
You don't want to use foreach as you'll always be needing two array elements. Note that this snippet does not protect you from 0 values. These will make your script fail.
$num = array(1, 2, 3, 4, 5, 3, 1);
$total = 0;
// The number of percent changes is one less than
// the size of your array.
$count = count($num) - 1;
// Array indexes start at 0
for ($i = 0; $i < $count; $i++) {
// The current number is $num[$i], and the
// next is $num[$i + 1]; knowing that it's
// pretty easy to compare them.
if ($num[$i] < $num[$i + 1]) {
$total += (100 * $num[$i] / $num[$i + 1]);
}
else {
$total += (-100 * $num[$i + 1] / $num[$i]);
};
};
echo ($total / $count);

Categories