Hi, I would really appreciate if I could be helped on the following PHP code.
I have two arrays.

1) $user
2) $usertotal

$user can have as many names stored in it.
Example:
$user[0]="John";
$user[1]="Sean";
$user[2]="Nick";
$user[3]="Jay";
................
................
Similary,
$usertotal can have as many amount stored in it.
Example:
$usertotal[0]=100;
$usertotal[1]=50;
$usertotal[2]=150;
$usertotal[3]=0;
................
................
I am trying to build a finance related program where for example : they all go on a vacation and promise to divide the total expense of the vacation evenly among themselves (later). When they started, not all of them had equal amount of money with them.

$user[i] has spent $usertotal[i] amount of money. For example in this case, John spent 100 dollars and Jay spent 0 dollars.
I also have a variable $average which is the average of all amount based on the number of users.

Now, what i am trying to do is keep a record of how much one user owes to another user since they promised to divide the total among themselves and each guy has to pay the average.

I am trying to compare each person's expense with $average and based on the difference the person should either pay to another person or receive money from another person based on how much he spent.

Logic :

// the average is 100+50+150+0 = 300/4 = 75
// Since John paid 100 he has to receive (100-75=25) from the rest of the guys.
// Sean paid only 50, so he has to pay 25 to either John or Nick
// Nick spent 150 so he needs 75 payback from the rest.
// Jay did not have money during the trip so now he owes 75 to someone who alredy spent more than 75 (may be Nick and John). he should also be able to break it down and pay multiple persons if need be.

---------------------------------------------------------------------------------------
OUTPUT :
Sean has to pay 25 to John
Jay has to pay 75 to Nick

---------------------------------------------------------------------------------------

See, this way all of the guys ended up paying 75 as their part.
Suggestions and ideas would be highly appreciated. Thanks in advance.

Recommended Answers

All 9 Replies

$total = 0;
$i = 0;
foreach($usertotal as $k=>$v){
    $total += $v;
    $i++;
}
$average = $total/$i;
foreach($usertotal as $k=>$v){
    $topay = $average-$v;
    if($topay == 0){
        echo $users[$k].' has paid his share'."<br/>\r\n";
    }elseif($topay >0){
        echo $users[$k].' needs to pay: £'.$topay."<br/>\r\n";
    }else{
        echo $users[$k].' needsto recieve: £'.abs($topay)."<br/>\r\n";
    }
}

The nice logic you have for that setup could get really complex on some situations it is probably better to just list out who needs to pay what and who needs to get paid what, that sort of logic gets very complex to put into a computer.

Sounds like you need to database it though if you are really going to go ahead with it mysql is very good to work with in php and store currency either in pence as an integar or in pounds as a decimal, not float (float doesnt store values very accurately).

note: foreach() + arrays == 'awesome'

Thank you so much Biiim, but I still have to track down or calculate who-owes-who transactions. I have been looking at php objects but no luck so far.

Maybe this would work, i've not tested it.

arsort() orders highest first so the biggerpayments are done at the start. thinking about it the $recA array probably needs sorting on each loop of the $payA array.

$total = 0;
$i = 0;
foreach($usertotal as $k=>$v){
    $total += $v;
    $i++;
}
$average = $total/$i;
$payA = array();
$recA = array();
foreach($usertotal as $k=>$v){
    $topay = $average-$v;
    if($topay == 0){
        echo $users[$k].' has paid his share'."<br/>\r\n";
    }elseif($topay >0){
        echo $users[$k].' needs to pay: £'.$topay."<br/>\r\n";
        $payA[$k] = $topay;
    }else{
        echo $users[$k].' needsto recieve: £'.abs($topay)."<br/>\r\n";
        $recA[$k] = abs($topay);
    }
}
arsort($recA);
arsort($payA);

foreach($payA as $k=>$v){
    foreach($recA as $key=>$value){
        if($v > $value){
            echo $users[$k].' Pays back: '.$users[$key].' £'.$value."<br/>\r\n";
            $v = $v - $value;
            $recA[$key] = 0;
        }elseif($v < $value){
            echo $users[$k].' Pays back: '.$users[$key].' £'.$v."<br/>\r\n";
            $recA[$key] = $value - $v;
            $payA[$k] = 0;
        }else{
            echo $users[$k].' Pays back: '.$users[$key].' £'.$value."<br/>\r\n";
            $recA[$key] = 0;
            $payA[$k] = 0;
        }
    }
}   

Biiim,

Thanks a ton. You Rock man! It works flawlessly. :)

hi Biiim,

the code works fine normally. For a specific case though its kinda a giving wrong output.
if the following users have spent as follows :

ray: $12.44
rob: $0.00
paul: $0.00
spence: $15.00

the code is giving the output as :

paul pays back to spence $6.86
paul pays back to ray $5.58
rob pays back to spence $1.28
rob pays back to ray $0.00

here paul is having to pay more than he has to and rob is paying much less.

The code did work for larger data volumes where each user spent more than $0.

Ah sorry im not around as much anymore, just have to step it through logically - it can be pretty hard to map it all out in your head what is happening.

So in this situation:

ray: $12.44
rob: $0.00
paul: $0.00
spence: $15.00

The Total is 27.44, fair share is $6.86.

 foreach($usertotal as $k=>$v){
     $topay = $average-$v;
     if($topay == 0){
         echo $users[$k].' has paid his share'."<br/>\r\n";
     }elseif($topay >0){
         echo $users[$k].' needs to pay: £'.$topay."<br/>\r\n";
         $payA[$k] = $topay;
     }else{
         echo $users[$k].' needsto recieve: £'.abs($topay)."<br/>\r\n";
         $recA[$k] = abs($topay);
     }
 }

so $payA contains Paul and Rob (or should do) and they need to pay $6.86 each and $recA contains Spence and Ray. Rays needs $5.58 and Spence needs $8.14. If not this needs to be corrected in this foreach loop.

arsort($recA);
arsort($payA);

Sort so largest values first(doing smaller values or random order will make people need to pay more different people)

 foreach($payA as $k=>$v){
     foreach($recA as $key=>$value){
         if($v > $value){
             echo $users[$k].' Pays back: '.$users[$key].' £'.$value."<br/>\r\n";
             $v = $v - $value;
             $recA[$key] = 0;
         }elseif($v < $value){
             echo $users[$k].' Pays back: '.$users[$key].' £'.$v."<br/>\r\n";
             $recA[$key] = $value - $v;
             $payA[$k] = 0;
         }else{
             echo $users[$k].' Pays back: '.$users[$key].' £'.$value."<br/>\r\n";
             $recA[$key] = 0;
             $payA[$k] = 0;
         }
     }
 }

So loop starts, from your reply first person is Paul.
Loop starts on the second array, picking Spence first since he needs the most.
Money Paul needs to pay is less than What spence need so second if fires(}elseif($v < $value){)
$recA[$key] = $value - $v This takes off the money paul has paid to Spence, so spence now needs $1.28
$payA[$k] = 0 This "should" be setting how much Paul has to pay to 0, i suspect it isn't doing what i intended.

Second iteration of the $recA starts:
Ray needs $5.58, Paul should have already paid all he owes to Spence so he owes 0. php shouldnt bother echoing this part out, cause its irrelevant but look what it does!

paul pays back to ray $5.58

He shouldnt have any left. I think that is because updating the $payA doesn't update the current foreach loop through the array - i'm learning too - so the fix for that should be something like this:

foreach($payA as $k=>$v){
    arsort($recA);//after first person paid re-sort array so person who needs to recieve most at top
    foreach($recA as $key=>$value){
        if($v == 0){
            //do nothing
        }elseif($v > $value){
            echo $users[$k].' Pays back: '.$users[$key].' £'.$value."<br/>\r\n";
            $v = $v - $value;
            $payA[$k] = $payA[$k] - $value;
            $recA[$key] = 0;
        }elseif($v < $value){
            echo $users[$k].' Pays back: '.$users[$key].' £'.$v."<br/>\r\n";
            $recA[$key] = $value - $v;
            $payA[$k] = 0;
            $v = 0;//tell current loop this person doesn't owe anymore
        }else{
            echo $users[$k].' Pays back: '.$users[$key].' £'.$value."<br/>\r\n";
            $recA[$key] = 0;
            $payA[$k] = 0;
            $v = 0;
        }
    }
}

Beautiful ! works like a charm :) Thank you.

You're welcome :)
Didn't even think it would be possible when i first read what you wanted

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.