Using For loop inside function - not returning all values - php

I am having problems displaying the results of function calculateGrowth. As shown below, I would like to find the results for each day of a 10 day period. I used a for loop for obvious reasons. But when I try to display results, all I get back is one result.
function calculateGrowth(){
$days = 0;
$growth = 10;
for($days = 0; $days < 10; $days++){
$totalGrowth = $growth * pow(2, $days/10);
}
return $totalGrowth;
}
Current Output
18.6606598307
Desired Output
Day Growth
1 - result
. - result
. - result
10

$totalGrowth = $growth * pow(2, $days/10);
Should be
$totalGrowth[] = $growth * pow(2, $days/10);
^^
So that it becomes an array and contains all the values that you add to it, rather than being a string which gets overwritten on every iteration of the loop.

It sounds like what you're trying to get this:
function calculateGrowth() {
list($days, $growth, $table) = array(range(1, 10), 10, array());
foreach ($days as $day) {
$table[$day] = $growth * pow(2, $day/10);
}
return $table;
}

It is correct as your final loop is doing this
$totalGrowth = 10 * pow(2, 9/10)
$totalGrowth = 10*1.8660659830736;
$totalGrowth = 18.660659830736;
Edit : Removed last comment

Related

How to subtract time from time array using php?

Hello seniors I have a question related to some PHP script.
I have an array containing time => ['12:10', '4:16', '2:5'] and have one html form containing input field of type 'number'.
I want when I enter some value in my form input field for example I enter 7, so after submitting the form in back-end the number 7 which i enter in input field is subtracted from the array which I mentioned above and I will get the result array like:
['5:10', '4:16', '2:5']
I have tried something like that but not able to implement my logic
$val = array(1, 0, 2, 1, 1);
$subtract = 3.5;
foreach ($val as $key => $item) {
if ($subtract >= $item) {
$subtract -= $item;
$val[$key] = 0;
} else {
$val[$key] -= $subtract;
$subtract = 0;
}
}
Any kind of help is highly appreciated
You can use Carbon library for date/time manipulation:
<?php
use Carbon\Carbon;
$times = ['17:46', '03:05', '21:56'];
$timeshift = 3;
$new_times = array_map(
fn($t) => Carbon::createFromFormat('H:i', $t)
->subHours($timeshift)
->format('H:i'),
$times
);
Test Carbon library online
No need for library, just convert your first array to seconds: 1 hour = 3600 ; 1 minute = 60 ; 12:10 is 12 x 3600 + 10 x 60, then you do the same thing to your $_POST value, then use gmdate() to retrieve the original format of your array
$myTimes=array('12:10', '4:16', '2:5');
//do the math
$splittedTime = explode(":", $myTimes[0]); //in your case
$timeInSeconds = $splittedTime[0] * 3600 + $splittedTime[1] * 60 ;
//do the same thing to your your $_POST value if needed or simply
$totalReduceby = 7 * 3600;
// get new total of seconds
$newTime= $timeInSeconds - $totalReduceby;
$result = ltrim(gmdate("H:i", $newTime),0); //ltrim to remove the leading 0
$myTimes=array($result, '4:16', '2:5');
//print_r($myTimes);
time => ['12:10', '4:16', '2:5']
[...]
the number 7 which i enter in input field is subtracted from the array
I will get the result array like: ['5:10', '4:16', '2:5']
Your example is a little ambiguous. Do you only want to subtract the field value from the first element of the array, always? Or only from those elements which are greater than the submitted value?
It's pretty straightforward to subtract minutes from a mm:ss time string; simplest is probably to generalize so that the amount to subtract is also allowed to be mm:ss instead of always being a whole number of minutes. I would just explode both of them, turn them into total seconds (minutes*60+seconds), subtract those, and then turn back into mm:ss. Both conversions might be worth their own functions:
function mmssToSeconds($timeStr) {
if (str_contains($timeStr, ':')) {
list($min, $sec) = explode(':', $timeStr);
} else {
list($min, $sec) = array($timeStr, 0);
}
if ($min < 0) {
return 60*$min - $sec;
} else {
return 60*$min + $sec;
}
}
function secondsToMmss($seconds) {
$abs = abs($seconds);
$sgn = $seconds / $abs;
$min = floor($abs / 60);
$sec = $abs % 60;
return ($sgn < 0 ? '-' : '').sprintf('%d:%02d', $min, $sec);
}
And then the subtraction is easy:
function subtractMinutes($from, $delta) {
return secondsToMmss(mmssToSeconds($from) - mmssToSeconds($delta));
}
If you want to subtract from each element that is big enough, you could use a loop like this:
foreach ($ary['time'] as $i => $t) {
if ((int)$t > $subtract) {
$ary['time'][$i] = subtractMinutes($t, $subtract);
}
}
The comparison works because the cast from string to int ignores everything after the first non-digit, so '12:10' just becomes 12, which is > 7.

PHP divide by number but if not equal to number

I am trying to divide number to geners but if after that its less than 16 I want it to add the numbers from the less to 16 to the first gener in foreach.
$geners = explode(",", $post['geners']); // $post['geners'] = 12,26,988
$count = count($geners); // For example : 3
$calc = (16 / $count); / 5.6666
$total_each = number_format($calc, 0); // 5
$total = ( $count * $total_each); // 15
foreach ($geners as $key=>$gener){
$gener_each = $total_each;
if($total < 16){ // if 15 < 16
$minus_16 = 16 - $total; // 15-16 = 1
$gener_each[0]=$gener_each[0]+$minus_16; // First gener need to add $minus_16
}
echo $gener_each; // Need to be 6,5,5
}
It sounds like you need to divide 16 by an arbitrary number, create an array holding the same number of instances of that result as you have geners, round each instance of the divided result down to the nearest whole number, and then apply any remaining difference from a decimal result to the first in the set.
The following is untested, but have a look:
$geners = explode(',', $post['geners']);
$firstGener = current($geners);
$count = count($geners);
$calc = (16 / $count);
$floor = floor($calc);
$decimal = $calc - $floor;
$totals = [];
foreach ($geners as $gener) {
$totals[$gener] = $floor;
$totals[$firstGener] += $decimal;
}
//This is just in case a decimal result of an infinite number of digits, truncated by PHP itself, results in this value erroneously looking something like 5.9999999999999
$totals[$firstGener] = round($totals[$firstGener]);
//Since the value of $totals[$geners[0]] isn't done calculating until the completion of the above loop, presentation of each value needs to be handled in a separate one here:
foreach ($totals as $gener => $totals) {
echo "$gener - $total<br>";
}

How to generate random numbers to produce a non-standard distributionin PHP

I've searched through a number of similar questions, but unfortunately I haven't been able to find an answer to this problem. I hope someone can point me in the right direction.
I need to come up with a PHP function which will produce a random number within a set range and mean. The range, in my case, will always be 1 to 100. The mean could be anything within the range.
For example...
r = f(x)
where...
r = the resulting random number
x = the mean
...running this function in a loop should produce random values where the average of the resulting values should be very close to x. (The more times we loop the closer we get to x)
Running the function in a loop, assuming x = 10, should produce a curve similar to this:
+
+ +
+ +
+ +
+ +
Where the curve starts at 1, peeks at 10, and ends at 100.
Unfortunately, I'm not well versed in statistics. Perhaps someone can help me word this problem correctly to find a solution?
interesting question. I'll sum it up:
We need a funcion f(x)
f returns an integer
if we run f a million times the average of the integer is x(or very close at least)
I am sure there are several approaches, but this uses the binomial distribution: http://en.wikipedia.org/wiki/Binomial_distribution
Here is the code:
function f($x){
$min = 0;
$max = 100;
$curve = 1.1;
$mean = $x;
$precision = 5; //higher is more precise but slower
$dist = array();
$lastval = $precision;
$belowsize = $mean-$min;
$abovesize = $max-$mean;
$belowfactor = pow(pow($curve,50),1/$belowsize);
$left = 0;
for($i = $min; $i< $mean; $i++){
$dist[$i] = round($lastval*$belowfactor);
$lastval = $lastval*$belowfactor;
$left += $dist[$i];
}
$dist[$mean] = round($lastval*$belowfactor);
$abovefactor = pow($left,1/$abovesize);
for($i = $mean+1; $i <= $max; $i++){
$dist[$i] = round($left-$left/$abovefactor);
$left = $left/$abovefactor;
}
$map = array();
foreach ($dist as $int => $quantity) {
for ($x = 0; $x < $quantity; $x++) {
$map[] = $int;
}
}
shuffle($map);
return current($map);
}
You can test it out like this(worked for me):
$results = array();
for($i = 0;$i<100;$i++){
$results[] = f(20);
}
$average = array_sum($results) / count($results);
echo $average;
It gives a distribution curve that looks like this:
I'm not sure if I got what you mean, even if I didn't this is still a pretty neat snippet:
<?php
function array_avg($array) { // Returns the average (mean) of the numbers in an array
return array_sum($array)/count($array);
}
function randomFromMean($x, $min = 1, $max = 100, $leniency = 3) {
/*
$x The number that you want to get close to
$min The minimum number in the range
$max Self-explanatory
$leniency How far off of $x can the result be
*/
$res = [mt_rand($min,$max)];
while (true) {
$res_avg = array_avg($res);
if ($res_avg >= ($x - $leniency) && $res_avg <= ($x + $leniency)) {
return $res;
break;
}
else if ($res_avg > $x && $res_avg < $max) {
array_push($res,mt_rand($min, $x));
}
else if ($res_avg > $min && $res_avg < $x) {
array_push($res, mt_rand($x,$max));
}
}
}
$res = randomFromMean(22); // This function returns an array of random numbers that have a mean close to the first param.
?>
If you then var_dump($res), You get something like this:
array (size=4)
0 => int 18
1 => int 54
2 => int 22
3 => int 4
EDIT: Using a low value for $leniency (like 1 or 2) will result in huge arrays, since testing, I recommend a leniency of around 3.

Add up numbers in a for each PHP?

I'm trying to add some numbers in a foreach loop in my PHP code. I am getting a percentage of numbers in a while loop in my MySQL query for each result that I get in my PHP page.
All I need to do is to add up the final values in and show them as total.
This is how I make up the percentage in my while loop in my MySQL query:
$percentage = 10;
$totalWidth = $fees;
$new_width = ($percentage / 100) * $totalWidth;
The $fees value is dynamic and it is different for each result in my while loop. the code above works as it should.
Now I want to add up all the values of $new_width. For example:
If one result's $new_width is 25 and the other one is 10 and another one is 5, I need to do this: $total = 25 + 10 + 5;
So I tried something like this:
$total = 0;
foreach($new_width as $var) {
$total = $var + $var;
}
echo $total;
but the above code doesn't really make sense and it won't do anything at all.
Could someone please advise on this matter?
First you want to change this line in your while loop so you get an array:
$new_width = ($percentage / 100) * $totalWidth;
to this:
//Declare it as an array before your while loop
$new_width = array();
//In your while loop
$new_width[] = ($percentage / 100) * $totalWidth;
//^^ See here
After this you just have to change the line in your foreach loop like this:
$total = $var + $var;
to this:
$total += $var;
(If you want you also can do this in your while loop)
If you have an array of numbers and you want to calculate the sum of those numbers, you should use array_sum().
According to the logic, you are setting the total to 2 X $var.
My answer is very similar, but you add it to the total which is outside of the loop and the value will keep growing:
$total = 0;
foreach($new_width as $var) {
$total += $var;
}
echo $total;
Or simply as stated before, if it is the only value in the array:
$total = array_sum($new_width);

Fill in absent elements in an array

I have a code that generates total posts from a database per hour for the latest 10 hours. Now, the problem is that only hours with posts are displayed, but that won't work for me because i want to display the whole thing as a chart.
Example of the current array:
array("12"=>"20403",
"15"=>"17017",
"17"=>"84013");
The keys represent the hour in a 24 format. So what i need is a function that fills in the empty hours with 0 value.
Example:
$currenthour=date('H'); // i think it may be based on the latest hour.
array("11"="0",
"12"=>"20403",
"13"=>"0",
"14"=>"0",
"15"=>"17017",
"16"=>"0",
"17"=>"84013",
"18"=>"0",
"19"=>"0",
"20"=>"0");
Thanks!
foreach(range(0, 23) as $hour)
if(!isset($ary[$hour]))
$ary[$hour] = 0;
ksort($ary);
to fill in only last hours you may need something like
function last_hours($hour, $cnt) {
return $hour < $cnt - 1 ?
array_merge(range($hour, 0), range(23, 25 - $cnt + $hour)) :
range($hour, $hour - $cnt + 1);
}
and then
$now = date("G");
$new_array = array();
foreach(last_hours($now, 10) as $hour)
$new_array[$hour] = isset($ary[$hour]) ? $ary[$hour] : 0;
Use array_fill OR do it with a loop (assuming $hours is your array:
$currenthour=date('H');
for($i = $currenthour; $i < 23; $i++)
if(!isset($hours[$i]))
$hours[$i] = 0;
You can simply iterate through the array, and see if the value at the index is set. Like this:
Edit with your the last 10 hours:
$currenthour=date('H')
$beginrange = $currenthour - 10
if ($beginrange =< 0)
$beginrange = 23 + $beginrange
$endrange = $currenthour
//set up the for loop
foreach(range($beginrange, $endrange) as $i)
//check if the element is set
if(!isset($array[$i]))
// set it
$array[$i] = 0;

Categories