I am trying to do a Drug Half life calculator with PHP. I want to pass in the amount of the drug taken per day in MG's and pass in the Half-life hours, then it will calculate how much of the drug is left after X amount of time and how much is still left from previous doses.
So far this is what I have...
function calcHalfLife( $mgTaken , $drugHalfLifeHours , $day = 1 ) {
//total number of half-lifes elapsed
$total_half_lifes = ($day * 24) / $drugHalfLifeHours;
//total reduction in dosage
$reductionFactor = pow( 0.5 , $total_half_lifes );
//return the current dosage in the person's system
return round( $mgTaken * $reductionFactor , 8 );
}
Then I am working on this function below which will let me pass in an Array of Days and the MG taken for each day, the function should then iterate the array and run the function above on each day's value.
function HalfLifeChart(array $days, $drugHalfLifeHours ) {
$out = array();
foreach ($days as $day => $dosage) {
$out[$day] = calcHalfLife( $dosage , $drugHalfLifeHours , 1 );
}
return $out;
}
Example usage...
$day = array(1 => 30,
2 => 0,
3 => 0,
4 => 40,
5 => 30,
6 => 10,
7 => 60);
echo '<br><pre>';
print_r(HalfLifeChart( $day, 4.5));
echo '</pre><br><br>';
Now I have a pretty good start but the HalfLifeChart function is where I need to do more work, right now it will run the Half-life calculations on the number passed for each day which is good, but I need to get the result from the previous day and add that to the MG taken on the current day and then run the Calculations on that number.
So for example, if I have 0.8043mg left from the previous day and I took 30mg today, then the calculation should be ran on 0.8043 + 30 and then pass that result through my Half life calculator function.
I am not sure how to grab the result from the previous day though, any help please?
Why don't you store the result of the previous day on another variable?
Something like:
function HalfLifeChart(array $days, $drugHalfLifeHours ) {
$out = array();
$prevDay = 0;
foreach ($days as $k => $v) {
$out[$k] = calcHalfLife( $v , $drugHalfLifeHours , 1 ); //change this
$prevDay = $out[$k];
}
return $out;
}
function HalfLifeChart(array $days, $drugHalfLifeHours ) {
$out=array();
$remains=0;
foreach ($days as $day => $dosage) {
$total=$remains+$dosage;
$out[$day]=$total;
$remains=calcHalfLife( $total , $drugHalfLifeHours , 1 );
}
return $out;
}
gives you
print_r(HalfLifeChart( $day, 4.5));
Array
(
[1] => 30
[2] => 0.74409424
[3] => 0.01845587
[4] => 40.00045776
[5] => 30.99213701
[6] => 10.76870236
[7] => 60.26709765
)
Just store it.
function HalfLifeChart(array $days, $drugHalfLifeHours ) {
$out = array();
$yesterday = 0;
foreach ($days as $k => $v) {
$out[$k] = calcHalfLife($v + $yesterday, $drugHalfLifeHours, 1);
$yesterday = $out[$k];
}
return $out;
}
Related
I have a question about how to make an iteration. I want to place a total row after each item in the array if the next element in the array matches a specific condition. Spesific conditions have logic like this
the data like this
if i request a qty for example = 60 the result i hope like this
you can see
data[2] = 01/03/2020 just took 10 out of 40
$iter = new \ArrayIterator($values);
$sum = 0;
foreach($values as $key => $value) {
$nextValue = $iter->current();
$iter->next();
$nextKey = $iter->key();
if(condition) {
$sum += $value;
}
}
dd($iter);
how to make this logic work on php language/ laravel?
Following logic might help you on your way:
<?php
$stock = [
'01/01/2020' => 20,
'01/02/2020' => 30,
'01/03/2020' => 40
];
showStatus($stock, 'in stock - before transaction');
$demand = 60;
foreach ($stock as $key => $value) {
if ($value <= $demand) {
$stock[$key] = 0;
$supplied[$key] = $value;
$demand -= $value;
} else {
$stock[$key] -= $demand;
$supplied[$key] = $value - ($value - $demand);
$demand = 0;
}
}
showStatus($supplied, 'supplied');
showStatus($stock, 'in stock - after transaction');
function showStatus($arr = [], $msg = '')
{
echo $msg;
echo '<pre>';
print_r($arr);
echo '</pre>';
}
?>
**Output:**
in stock - before transaction
Array
(
[01/01/2020] => 20
[01/02/2020] => 30
[01/03/2020] => 40
)
supplied
Array
(
[01/01/2020] => 20
[01/02/2020] => 30
[01/03/2020] => 10
)
in stock - after transaction
Array
(
[01/01/2020] => 0
[01/02/2020] => 0
[01/03/2020] => 30
)
Working demo
I'm not sure I've understood you correctly but this might help:
$values = [
'01/01/2020' => 20,
'01/02/2020' => 30,
'01/03/2020' => 40
];
$demand = 60;
$total = array_sum($values);
$decrease = $total - $demand; //(20+30+40) - 60 = 30
$last_key = array_keys($values,end($values))[0]; //Is 01/03/2020 in this case
$values[$last_key] -= $decrease; //Decrease value with 30 calulated above
Would output:
Array
(
[01/01/2020] => 20
[01/02/2020] => 30
[01/03/2020] => 10
)
I have two different arrays like below,
month array
0 :November
1 :October
2 :September
3 :August
4 :July
5 :June
data array
0 {
profit :4045
month :June
}
1 {
profit :1161
month :August
}
2 {
profit :730
month :October
}
3 {
profit :1700
month :November
}
I need to compare these two arrays and make new array with profit as 0. Finally I want to get below array.
0 {
profit :4045
month :June
}
1 {
profit :0
month :July
}
2 {
profit :730
month :August
}
3 {
profit :0
month :September
}
4 {
profit :1700
month :October
}
5 {
profit :1700
month :November
}
I have tried below code, But it's not working
foreach ($month as $key => $value) {
if (array_key_exists($key, $data->month) {
$month[$key] = $data[$key];
} else {
$month[$key] = 0;
}
}
Ho can i make this array using month and data array?
foreach loops should do it
$month = array('November', 'October', 'September', 'August', 'July', 'June');
$data = array(
array('profit' => 4045, 'month' => 'June'),
array('profit' => 1161, 'month' => 'August'),
array('profit' => 730, 'month' => 'October'),
array('profit' => 1700, 'month' => 'November')
);
// output and temp arrays
$output = [];
$temp = [];
// Loop thru each data and set month as key, profit as value
foreach ($data as $value) {
$temp[$value['month']] = $value['profit'];
}
// Reverse month array
$month = array_reverse($month, true);
// Loop thru each month, check if month exist on temp, if not profit stays 0
foreach ($month as $value) {
$profit = 0;
if (array_key_exists($value, $temp)) {
$profit = $temp[$value];
}
$output[] = array('profit' => $profit, 'month' => $value);
}
// Output
echo '<pre>';
print_r($output);
I have a script that queries an API and finds records within the last day.
I'd like to then loop through these results and solely get those within the last hour.
Can someone explain how I do this?
This is my array of daily results:
array(2) {
[0]=>
array(36) {
["CallRef"]=> string(10) "1234567891"
["CallStartTime"]=> string(8) "08:18:30"
}
[1]=>
array(36) {
["CallRef"]=> string(10) "1234567892"
["CallStartTime"]=> string(8) "14:04:20"
}
}
It's 14:40 here in the UK so my script should just grab the 2nd item from the array.
How about this?
$apiElements = [
['CallRef' => '1234567891', 'CallStartTime' => '08:18:30'],
['CallRef' => '1234567892', 'CallStartTime' => '14:04:20'],
];
$currentFormatted = (new DateTime())->format('H');
$startOfHour = DateTime::createFromFormat('H:i:s', $currentFormatted . ':00:00');
$endOfHour = DateTime::createFromFormat('H:i:s', $currentFormatted . ':59:59');
$callsInHour = array_filter($apiElements, function($element) use ($startOfHour, $endOfHour) {
$dt = DateTime::createFromFormat('H:i:s', $element['CallStartTime']);
return $dt >= $startOfHour && $dt <= $endOfHour;
});
Totally untested, but give it a try.
Next time, please post what code you tried...
Theres multiple ways to do this. You can get a Unix timestmap from a hour ago: strtotime('-1 hour'). You can explode the time on every : in the time and take the 2nd result from the explode result.
foreach ($array as $value){
$exploded=explode(":",$value['CallStartTime']);
if(date('H')-1>$exploded[1]){
//This means it's an hour ago.
}
}
Replace $allResults and try this:
date_default_timezone_set('UTC');
$hourAgo = strtotime(date('H:i:s')) - 3600;
foreach ($allResults as $result){
if(strtotime($result["CallStartTime"]) > $hourAgo){
var_dump($result);
}
}
More flexible solution:
First you need a function to convert time to seconds
function convertTimeToSeconds($hhmmss)
{
//correct format if needed
list($hours, $minutes, $seconds) = explode(':', $hhmmss);
return $hours * 3600 + $minutes * 60 + $seconds;
}
And then you just can use array_filter function
$now = date('H:i:s');
$nowSeconds = convertTimeToSeconds($now);
$filterFunction = function ($value) use ($nowSeconds) {
return ($nowSeconds - convertTimeToSeconds($value['CallStartTime'])) < 3600; //3600 seconds = hour
};
$filteredList = array_filter($array, $filterFunction);
All together https://3v4l.org/icAmp
I suppose you have this array
Array
(
[0] => Array
(
[CallRef] => 1234567892
[CallStartTime] => 21:04:20
)
[1] => Array
(
[CallRef] => 1234567892
[CallStartTime] => 09:08:08
)
[2] => Array
(
[CallRef] => 1234567892
[CallStartTime] => 08:11:08
)
[3] => Array
(
[CallRef] => 1234567892
[CallStartTime] => 20:59:08
)
)
And so i tried this
<?php
$arr = array(
"0" => array (
"CallRef" => 1234567892,
"CallStartTime" => "21:04:20"
),
"1" => array (
"CallRef" => 1234567892,
"CallStartTime" => "09:08:08"
),
"2" => array (
"CallRef" => 1234567892,
"CallStartTime" => "08:11:08"
),
"3" => array (
"CallRef" => 1234567892,
"CallStartTime" => "20:59:08"
)
);
//echo "<pre>";print_r($arr);die;
date_default_timezone_set('Asia/kolkata');//set your timezone
$currentTime = date('H:i:s');//getting current time
$lastHourTime = date('H:i:s', strtotime('-1 hour'));//getting last hour time
$result = array();
foreach ($arr as $singlearr){
if(strtotime($singlearr['CallStartTime']) >= strtotime($lastHourTime) && strtotime($singlearr['CallStartTime']) <= strtotime($currentTime)){
$result[] = $singlearr;
}else{
}
}
echo "<pre>";print_r($result);die;//this gives me last hour records only
Check Demo When you check demo All records which have time > last hour will return otherwise it will return empty array
May be it can help!
I'm trying to create an algorithm that returns a price depending on number of hours. But the distance between the number of hours are varying. For example I have an array:
$set = [
1 => 0.5,
2 => 1,
3 => 1.5,
4 => 2,
5 => 2.5,
12 => 4
];
$value = 3;
end($set);
$limit = (int)key($set);
foreach($set as $v => $k) {
// WRONG, doesn't account for varying distance
if($value >= $v && $value <= $v) {
if($value <= $limit) {
return $k;
} else {
return false;
}
}
}
The trouble is, the distance between 5 and 12 register as null. I might as well use $value == $v instead as the line I've marked as incorrect does anyway.
So I was wondering if there was a better way to round up to the next index in that array and return the value for it?
Cheers in advance!
Try this:
$set = array(1 => 0.5, 2 => 1, 3 => 1.5, 4 => 2, 5 => 2.5, 12 => 4);
function whatever(idx, ary){
if(in_array(idx, array_keys(ary))){
return ary[idx];
}
else{
foreach(ary as $i => $v){
if($i > idx){
return $v;
}
}
}
return false;
}
echo whatever(7, $set);
The problem is that $v is a single value, so $value >= $v && $value <= $v is equivalent to $value == $v.
Instead, consider that if the loop hasn't ended, then the cutoff hasn't been reached yet - and a current "best price" is recorded. This requires that the keys are iterated in a well-ordered manner that can be stepped, but the logic can be updated for a descending order as well.
$price_chart = [
1 => 0.5,
2 => 1,
3 => 1.5,
4 => 2,
5 => 2.5,
12 => 4
];
function get_price ($hours) {
global $price_chart;
$best_price = 0;
foreach($price_chart as $min_hours => $price) {
if($hours >= $min_hours) {
// continue to next higher bracket, but remember the best price
// which is issued for this time bracket
$best_price = $price;
continue;
} else {
// "before" the next time cut-off, $hours < $min_hours
return $best_price;
}
}
// $hours > all $min_hours
return $best_price;
}
See the ideone demo. This code could also be updated to "fill in" the $price_chart, such that a price could be found simply by $price_chart[$hours] - but such is left as an exercise.
Working with an array of dates (opening times for a business). I want to condense them to their briefest possible form.
So far, I started out with this structure
Array
(
[Mon] => 12noon-2:45pm, 5:30pm-10:30pm
[Tue] => 12noon-2:45pm, 5:30pm-10:30pm
[Wed] => 12noon-2:45pm, 5:30pm-10:30pm
[Thu] => 12noon-2:45pm, 5:30pm-10:30pm
[Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
What I want to achieve is this:
Array
(
[Mon-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
I've tried writing a recursive function and have managed to output this so far:
Array
(
[Mon-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Tue-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Wed-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Thu-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
Can anybody see a simple way of comparing the values and combining the keys where they're similar? My recursive function is basically two nested foreach() loops - not very elegant.
Thanks,
Matt
EDIT: Here's my code so far, which produces the 3rd array above (from the first one as input):
$last_time = array('t' => '', 'd' => ''); // blank array for looping
$i = 0;
foreach($final_times as $day=>$time) {
if($last_time['t'] != $time ) { // it's a new time
if($i != 0) { $print_times[] = $day . ' ' . $time; }
// only print if it's not the first, otherwise we get two mondays
} else { // this day has the same time as last time
$end_day = $day;
foreach($final_times as $day2=>$time2) {
if($time == $time2) {
$end_day = $day2;
}
}
$print_times[] = $last_time['d'] . '-' . $end_day . ' ' . $time;
}
$last_time = array('t' => $time, 'd' => $day);
$i++;
}
I don't think there is a particularly elegant solution to this. After much experimenting with the built in array_* functions trying to find a nice simple solution, I gave up and came up with this:
$lastStart = $last = $lastDay = null;
$new = array();
foreach ($arr as $day => $times) {
if ($times != $last) {
if ($last != null) {
$key = $lastStart == $lastDay ? $lastDay : $lastStart . '-' . $lastDay;
$new[$key] = $last;
}
$lastStart = $day;
$last = $times;
}
$lastDay = $day;
}
$key = $lastStart == $lastDay ? $lastDay : $lastStart . '-' . $lastDay;
$new[$key] = $last;
It only uses one foreach loop as opposed to your two, as it keeps a bunch of state. It'll only merge adjacent days together (i.e., you won't get something like Mon-Tue,Thu-Fri if Wednesday is changed, you'll get two separate entries).
I'd approach it by modelling it as a relational database:
day start end
1 12:00 14:45
1 17:30 22:30
...
Then its fairly easy to reduce - there are specific time intervals:
SELECT DISTINCT start, end
FROM timetable;
And these will occur on specific days:
SELECT start, end, GROUP_CONCAT(day) ORDER BY day SEPERATOR ','
FROM timetable
GROUP BY start,end
(this uses the MySQL-only 'group_concat' function - but the method is the same where this is not available)
would give:
12:00 14:45 1,2,3,4,5
17:30 22:30 1,2,3,4,5
12:00 23:00 6
12:00 21:30 7
Then it's fairly simple to work out consecutive date ranges from the list of days.
C.
As an alternative, I managed to cobble together a version using array_* functions. At some point though, 'elegance', 'efficiency' and 'readability' all packed up and left. It does, however, handle the edge cases I mentioned in the other answer, and it left me with a nice warm glow for proving it could be done in a functional manner (yet at the same time a sense of shame...)
$days = array_keys($arr);
$dayIndices = array_flip($days);
var_dump(array_flip(array_map(
function ($mydays) use($days, $dayIndices) {
return array_reduce($mydays,
function($l, $r) use($days, $dayIndices) {
if ($l == '') { return $r; }
if (substr($l, -3) == $days[$dayIndices[$r] - 1]) {
return ((strlen($l) > 3 && substr($l, -4, 1) == '-') ? substr($l, 0, -3) : $l) . '-' . $r;
}
return $l . ',' . $r;
}, '');
}, array_map(
function ($day) use ($arr) {
return array_keys($arr, $arr[$day]);
}, array_flip($arr)
)
)));
I tested it with this input:
'Mon' => '12noon-2:45pm, 5:30pm-10:30pm',
'Tue' => '12noon-2:45pm, 5:30pm-10:30pm',
'Wed' => '12noon-2:45pm, 5:30pm-10:00pm',
'Thu' => '12noon-2:45pm, 5:30pm-10:30pm',
'Fri' => '12noon-2:45pm, 5:30pm-10:00pm',
'Sat' => '12noon-2:45pm, 5:30pm-10:30pm',
'Sun' => '12noon-9:30pm'
And got this:
["Mon-Tue,Thu,Sat"]=> string(29) "12noon-2:45pm, 5:30pm-10:30pm"
["Wed,Fri"]=> string(29) "12noon-2:45pm, 5:30pm-10:00pm"
["Sun"]=> string(13) "12noon-9:30pm"
Basically, the array_map at the end transforms the input into an associative array of times to an array of days that they occur on. The large block of code before that reduces those days into a nicely formatted string using array_reduce, consulting the $days and $dayIndices arrays to check if days are consecutive or not.