0

I feel quite stupid for asking this as I feel I should have been able to figure this out, but alas I am spending too much time on it and getting frustrated, so I figured I would request some help. I have a PHP array that looks as follows. This is just an example as this project is a work in progress:

$donations = array(
    "2018 December" => array('30','20','100'),
    "2018 November" => array('10','5','200','1000')
);

I have made several attempts at nested for and foreach loops to try to get the values out, and I can get close, but I always seem to run into different road blocks. For example, I used to have the year and months as part of the sub array. I was able to successfully pull all the values out using a for and then foreach loop, but I could not figure out how to exclude the first two elements (year and month) in the foreach. Here is the ultimate goal...

Each sub array contains individual member donations in US dollars. The array may grow during the current month as more donations come in, but once the month rolls over, the next month sub array starts populating with donations and the previous month is "archived". I need to sum all the donations for each sub array and make each value available to be represented as a percentage (round to nearest integer) as part of a bar graph that displays on the webpage.

Can anyone please help me to formalize my process?

This is what I tried initially. This is using the older uglier array. It should be noted, this version currently does not round to nearest integer. Have not figured that part out yet either. These numbers just workout nicely in this example. Also, in case you are curious, $total is calculated separately in a different part of the page. $total = the operating costs per month for the group, but in this example I have manually set it to $100.

$donate = array(
    array("5","10"),
    array("20","30"),
    array("0"),
    array("0"),
    array("0")
);

$keydonate = array_keys($donate);
$taco = array();
for($i = 0; $i < count($donate); $i++) {
    foreach($donate[$keydonate[$i]] as $value) {
        $sum = $sum + $value;
        $taco[$i] = ($sum/$total)*100;
    }
}

This kinda works, but again, my logic is severely flawed here and this method has some pretty serious bugs. For example, the arrays keep adding to each other from previous months. Every month they need to reset back to default. Notice how in the screen shot, December is actually a sum of December and November and then on and on? Also, I like being able to add the month and year to the array as well, which this version is not capable of handling. I need some serious guidance and examples on the proper way to do this please. I know just enough PHP to be dangerous!

Thank you!

Progress bars

3
  • Are the percentages supposed to be the percentage of the total of that month out of the total of all the months? Commented Nov 27, 2018 at 23:42
  • In this example, the total represents the running expenses on a per month basis. There is no overlap at all between months. ie say it costs $100 to stay running each month. In this example 15% ($15) was donated during the month of november. Now, I know we're not in December yet, but again this is just an example. Technically according to the array, $50 was donated for the month of December, but it is displaying incorrectly. It is summing the $50 from Dec with the $15 from Nov. Make sense? All this is, is a simple way for members to see if we are fully funded for the current (and future) month. Commented Nov 27, 2018 at 23:48
  • Put $sum = 0; before foreach($donate[$keydonate to reset the sum before the next month calculations start Commented Nov 28, 2018 at 0:53

3 Answers 3

1

I added the month and year into the array like you said you wanted and make this little script that seems to do what you are asking if I understood your question correctly.

<?php
        //Enter your code here, enjoy!

$donations = array(
    array('2018', 'December', '30','20','100'),
    array('2018', 'November', '10','5','200','1000')
);

$total = 75;


$taco = array();
for($i = 0; $i < count($donations); $i++) {
    $sum = 0;
    for($j = 2; $j < count($donations[$i]); $j++) {
        $sum += $donations[$i][$j];
        }
        //echo $sum." ";
    $taco[$i] = ($sum/$total)*100;
}

for($i = 0; $i < count($donations); $i++){
    echo "Month ". $donations[$i][0]." ".$donations[$i][1]." raised ".$taco[$i]." % of monthly costs."."\r\n";
}

Is this more what your looking for? Output: enter image description here

Sign up to request clarification or add additional context in comments.

Comments

1

You were really close.

It looks like the only reason the code you tried wasn't working was that you weren't resetting the sum to zero for each month.

for($i = 0; $i < count($donate); $i++) {
    $sum = 0;                                        // <----- Like this
    foreach($donate[$keydonate[$i]] as $value) {
        $sum = $sum + $value;
        $taco[$i] = ($sum/$total)*100;
    }
}

There are some other things that could be optimized, but that should be all you need to get it working.


Some suggestions for optimization:

It's generally better to use a foreach loop to iterate an array. A for loop is generally better for doing something a fixed number of times. And calculating the percentage inside the inner loop is a bit wasteful (you're recalculating it for every number in the inner array, but only using the last one). You can calculate it after that loop ends instead.

foreach ($donate as $month => $values) {
    $sum = 0;
    foreach($values as $value) {
        $sum += $value;
    }
    $taco[$month] = ($sum/$total)*100;
}

Or even better, use a built in function to sum the inner array instead of another loop.

foreach ($donate as $month => $values) {
    $taco[$month] = array_sum($values) / $total * 100;
}

2 Comments

Will test in a moment. Trying to other suggestion at the moment (which was deleted just now for some reason). Thank you!
You're welcome! I think maybe they deleted the other answer because it calculated the percentage based on the grand total of all the values rather than a fixed number like you're using. They may edit it and undelete.
0

Well I wish the original guy that gave me this answer would not have deleted his post. The solution was correct! I just had to make a slight modification to suit my purposes. Here is the working solution with screenshot. Thank you mystery user! Thank you everyone else too for your time and submissions.

<?php
    //------------ MEMBER DONATIONS ------------
    $donations = [
        "2019 March" => ['100','8.61'],
        "2019 February" => ['0.12','0.45','1.76','4.23','1.23','9.34','2.34','1.23','5.55','9.21'],
        "2019 January" => ['10','10','10','10','5'],
        "2018 December" => ['0'],
        "2018 November" => ['10']
    ];
    //------------------------------------------

    $totalSum = 0;
    $monthlySums = [];
    $monthlyPercentages = [];
    foreach($donations as $month => $values) {
        $monthlySums[$month] = array_sum($values);
        $totalSum += $monthlySums[$month];
    }
    foreach($monthlySums as $month => $monthlySum) {
        $monthlyPercentages[$month] = round($monthlySum / $total * 100,2);
        if($monthlyPercentages[$month] > 100){
            $monthlyPercentages[$month] = 100;
        }
    }
?>

and then the HTML

    <?php
        foreach(array_keys($donations) as $month) {
            echo "<div class='prog-font'>". $month ."</div><div class='prog-cont'><div class='prog-fill' style='width:". $monthlyPercentages[$month] ."%'><span style='padding-left: 5px;'>". $monthlyPercentages[$month] ."%</span></div></div><div class='prog-goal'>Operating Expenses $". $total ."</div><br />";
        };
    ?>

enter image description here

I decided to allow two decimal places and I decided to include some simple limits to prevent the bar graph from spilling over. Ideally once one month is fully funded, the remainder would spillover to the next month, but for the time being I will deal with that manually. Will work on additional automation at a later date. Just nice to have this initially up and running. Thank you!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.