I am trying to loop through an array and calculate each value with next one. The data is like
[
['rate' => 1000, 'date' => '2017-07-10'],
['rate' => 2000, 'date' => '2017-08-14'],
['rate' => 3000, 'date' => '2017-08-18'],
['rate' => 1000, 'date' => '2017-07-23']
]
I have this [edited, following an example from another question in stackoverflow]:
#foreach ($users as $user)
#if ($user->admin_id == $active_user) // filtering users under this admin
#foreach ($userbillings as $userbilling)
#if($userbilling->user_id == $user->id) // filtering users
<?php
$count = count($userbilling->created_at);
$rates[] = $userbilling->rate;
$diff = 0;
for ($i=0; $i < $count; $i++) {
if (isset($rates[$i + 1])) {
$thisValue = $rates[$i];
$nextValue = $rates[$i + 1];
$diff = $nextValue - $thisValue;
}
}
echo $diff;
?>
#endif
#endforeach
#endif
#endforeach
This gives me result: 1000 2000 3000 1000 3000
What I want to achieve is to subtract first item from second, second item from third, third item from forth and so on, until it reaches to the last item. For last item, I want to keep the whole number.
I understand that I need to use array and loop here, and I have tried different ways for past 2 weeks, but cannot get even close.
Please suggest me how to make it work, or give me a guideline how I should proceed. I have searched plenty of questions here, but could not find anything right for my problem. If there is any, please suggest me the link.
You haven't specified your preferred output but assuming that you want to end up with an array result of the calculations for all pairs, plus the last element as-is, this should get you on the right track.
I would also second a comment above - do not do this sort of logic in a view as it belongs in a controller or somewhere like a service. Keep your views as simple as possible.
Not tested so please do so yourself:
<?php
$periods = [
['rate' => 1000, 'date' => '2017-07-14'],
['rate' => 3000, 'date' => '2017-08-18'],
['rate' => 2000, 'date' => '2017-08-10'],
['rate' => 3000, 'date' => '2017-08-15'],
['rate' => 1000, 'date' => '2017-08-23'],
];
$lastPeriod = count($periods) - 1;
$ratesForPeriods = [];
foreach ($periods as $index => $currentPeriod) {
if ($index === $lastPeriod) {
$ratesForPeriods[] = $currentPeriod; // add the last as-is
} else {
$nextPeriod = $periods[$index + 1];
$currentDate = new DateTime($currentPeriod['date']);
$interval = $currentDate->diff(new DateTime($nextPeriod['date']));
$ratesForPeriods[] = [
'from' => $currentPeriod['date'],
'to' => $nextPeriod['date'],
'rate' => $currentPeriod['rate'],
'days' => $interval->days,
'total' => $interval->days * $currentPeriod['rate'],
];
}
}
print_r($ratesForPeriods);
Yields:
Array
(
[0] => Array
(
[from] => 2017-07-14
[to] => 2017-08-18
[rate] => 1000
[days] => 35
[total] => 35000
)
[1] => Array
(
[from] => 2017-08-18
[to] => 2017-08-10
[rate] => 3000
[days] => 8
[total] => 24000
)
[2] => Array
(
[from] => 2017-08-10
[to] => 2017-08-15
[rate] => 2000
[days] => 5
[total] => 10000
)
[3] => Array
(
[from] => 2017-08-15
[to] => 2017-08-23
[rate] => 3000
[days] => 8
[total] => 24000
)
[4] => Array
(
[rate] => 1000
[date] => 2017-08-23
)
)
Hope this helps :)
Your question is not clear, but here is an example that might help you!
use array_slice() & array_sum()
$array = array( "0"=>1,"1"=>1,"2"=>5,"3"=>1,"4"=>1,"7"=>1,"8"=>3,"9"=>1);
$keys = array_keys($array);
$array = array_values($array);
$newArr = array();
foreach ($array as $key=>$val) {
$newArr[] = array_sum(array_slice($array, 0, $key+1));
}
$newArr = array_combine($keys, $newArr);
print '<pre>';
print_r($newArr);
print '</pre>';
Reference:
array_slice()
array_sum()
array_combine()
array_keys()
You can access the next item in foreach loop like following code :
foreach ($items as $key => $item)
{
echo !empty($items[$key+1]) ? ($items[$key+1]->rate - $item->rate) : $itema->rate;
}
Related
I have conditional function which their execution not running as per business meet which to be require transformation as with desired result. This function contain ranking and frequency which are part of multidimensional array and their execution of sum on based of some calculation
I want to add frequency on base of position of ranking which their execution partially run not accurate. could you please help me out.
<?php
$arr = array (
'AMXB 5321' => array(
array("course_title_code" => "AMB 5321",
"content" => "Course",
"total" => "303",
"count" => "85",
"ranking" => array(array(5),array(2,4,5)),
"frequency" => array(array(5),array(1,2,11))),
array("course_title_code" => "AMB 5321",
"content" => "Succeed in the course",
"total" => "300",
"count" => "85",
"ranking" => array(array(3,5),array(3,4,5)),
"frequency" => array(array(1,4),array(1,2,11))
)
));
array_walk($arr, function(&$v,$k){
foreach($v as $key => &$s){
$s['ranking'] = implode(',',range(1,5));
foreach($s['frequency'] as $key => &$value){
$temp = $value;
$value = (count($value) == 5) ? $value : array_merge(array_fill(0, 5 - count($value), 0), $temp);
if($key == 1){
for($i=0;$i<count($value);$i++){
$value[$i] += $s['frequency'][$key-1][$i];
}
$temFormat = implode(',',$s['frequency'][1]);
}
}
unset($s['frequency']);
$s['frequency'] = $temFormat;
}
});
echo "<pre>";
print_r($arr);
?>
Desired Result
Array
(
[AMXB 5321] => Array
(
[0] => Array
(
[course_title_code] => AMB 5321
[content] => Course
[total] => 303
[count] => 85
[ranking] => 1,2,3,4,5
[frequency] => 0,1,0,2,16
)
[1] => Array
(
[course_title_code] => AMB 5321
[content] => Succeed in the course
[total] => 300
[count] => 85
[ranking] => 1,2,3,4,5
[frequency] => 0,0,2,2,15
)
)
)
You can do that like this:
function calRanking($ranks, $freqs) {
$res = array_fill(0, 5, 0); // create array of 0
foreach($ranks as $k => $v) {
foreach(array_map(null, $v, $freqs[$k]) as $e) {
$res[$e[0]-1]+= $e[1]; //add the frequency according to rank key
}
}
return $res;
}
foreach($a as &$v) { // for each calculate and implode
$v["frequency"] = implode(',', calRanking($v["ranking"], $v["frequency"]));
$v["ranking"] = implode(',',range(1,5));
}
I assumed user with a lot of answer and reputation may build the question in more suite-able way for future learning...
Live example: 3v4l
Reference: array-fill, array-map
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
i have an array in php like this:
Array ( [0] => Array ( [post_date] => 2017-07-22 [num] => 1 )
[1] => Array ( [post_date] => 2017-07-24 [num] => 2 )
[2] => Array ( [post_date] => 2017-07-26 [num] => 5 ))
i want to change it to this array:
Array ( [0] => Array ( [post_date] => 2017-07-22 [num] => 1 )
[1] => Array ( [post_date] => 2017-07-23 [num] => 0 )
[2] => Array ( [post_date] => 2017-07-24 [num] => 2 )
[3] => Array ( [post_date] => 2017-07-25 [num] => 0 )
[4] => Array ( [post_date] => 2017-07-26 [num] => 5 ))
how to do this?
Try this code and hope it's clear enough, the idea behind this solution is very simple:
First we sort our array using a user-defined comparison function by the post_date column value, this will helps us later when looping over the dates.
After that we make sure that the array contains at least two value to compare by starting the for loop from 1 and make sure the size of the array is greater than 1.If not we return the array as it is.
$i = 1; $i < count($array); => count($array) > 1 => at least 2
values.
Next we calculate the difference between two consecutive post_date of the array, if the difference is 1 day so we have two consecutive days, else we have to add the next day to the array from the "$i" position of post_date by using this helpers function:
array_splice($array, $i, 0, [[
'post_date' => $date1->modify('+1 day')->format('Y-m-d'),
'num' => 0,
]]);
Which will add 1 day the post_date and push other values to the right of the array which make the size of the array bigger ( +1 value) and will add another iteration for the for loop.
At the end of the loop, we will get a full array of consecutives days as the OP want.
<?php
$array = [
['post_date' => '2017-07-22','num' => '1'],
['post_date' => '2017-07-26','num' => '5'],
['post_date' => '2017-07-24','num' => '2'],
];
sort($array);
$count = count($array);
for($i = 1; $i < $count; $i++) {
$date1 = new DateTime($array[$i-1]['post_date']);
$date2 = new DateTime($array[$i]['post_date']);
$diff = $date2->diff($date1)->format("%a");
if(1 < $diff) {
array_splice($array, $i, 0, [[
'post_date' => $date1->modify('+1 day')->format('Y-m-d'),
'num' => 0,
]]);
$count++;
}
}
echo "<pre>";
print_r($array);
the output :
Array
(
[0] => Array
(
[post_date] => 2017-07-22
[num] => 1
)
[1] => Array
(
[post_date] => 2017-07-23
[num] => 0
)
[2] => Array
(
[post_date] => 2017-07-24
[num] => 2
)
[3] => Array
(
[post_date] => 2017-07-25
[num] => 0
)
[4] => Array
(
[post_date] => 2017-07-26
[num] => 5
)
)
Hope my post will be helpful, Here we are using PHP Datetime
Try this code snippet here
<?php
ini_set('display_errors', 1);
$array=
array (
0 =>
array (
'post_date' => '2017-07-22',
'num' => '1',
),
1 =>
array (
'post_date' => '2017-07-24',
'num' => '2',
),
2 =>
array (
'post_date' => '2017-07-26',
'num' => '5',
),
);
$dates= array_column($array, 'num','post_date');
$firstDate=$currentDate=key($dates);
end($dates);
$lastDate=key($dates);
$result=array();
while(true)
{
if(isset($dates[$currentDate]))
{
$result[]=array('post_date'=>$currentDate,'num'=>$dates[$currentDate]);
}
else
{
$result[]=array('post_date'=>$currentDate,'num'=>0);
}
if($currentDate==$lastDate)
{
break;
}
$dateTimeObject= new DateTime($currentDate);
$dateTimeObject->add(new DateInterval("P1D"));
$currentDate = $dateTimeObject->format("Y-m-d");
}
print_r($result);
Try this code.If the dates are not in order then also this code works. I have added comment in code for understanding
<?php
$array = array(
array(
"post_date"=>"2017-07-22",
"num" =>1
),
array(
"post_date"=>"2017-07-24",
"num" =>2
),
array(
"post_date"=>"2017-07-26",
"num" =>5
),
);
$total = count($array);
$check_dates = array_column($array, "post_date"); //array of dates
asort($check_dates); //sort array by dates and keep keys
$start_date = reset($check_dates); //minimum date
$end_date = end($check_dates); //maximum date
$current_date = $start_date; //set current date to start date
$new_array = array(); //this will be your final array
while (strtotime($current_date) <= strtotime($end_date)) {
$search_val = array_search($current_date, $check_dates);
if($search_val > 0 || $search_val === 0)
{
$new_array[] = $array[$search_val];
}
else
{
$tmp_array=["post_date"=>$current_date,"num"=>0];
$new_array[] = $tmp_array;
}
$current_date = date("Y-m-d",strtotime('+1 day',strtotime($current_date))); //change current date
}
print_r($new_array);
You could define an array with the increased size which is capable of containing the whole dataset. You then could push all elements in it, and once you do that, using strtotime, you could sort the array to be as you wish.
<?php
$arr1 = $your_initial_array;
$arr2 = array_push($arr1, $your_values);
$arr3 = array();
$topop = 0;
for($x = 0; $x < count($arr2); $x++) {
for($i = 0; $i < count($arr2); $i++) {
if(strtotime($arr2[$i]['post_date'] > $latest) { // or < if you want
$topop = $i;
}
}
array_push($arr3, $arr2[$topop]);
unset($arr2[$topop]);
}
You repeat it so many times your array contains elements to be sure you have the right succession. Hope this helps!
Below is the array output which shows user data, month wise. I need to get the sum of ACTUAL_HOURS for different resources.
For below, sum of ACTUAL_HOURS for User 1 and User 2 for the month JUL-2015, should be 10 + 20 = 30.
Same goes for AUG-2015 which is 80 + 20 = 100
$user_array output
Array
(
[User 1] => Array
(
[JUL-2015] => Array
(
[SITE_STATUS] => Offshore
[ACTUAL_HOURS] => 10
[PROJECTED_HOURS] => 20
)
[AUG-2015] => Array
(
[SITE_STATUS] => Offshore
[ACTUAL_HOURS] => 80
[PROJECTED_HOURS] => 88
)
)
[User 2] => Array
(
[JUL-2015] => Array
(
[SITE_STATUS] => Offshore
[ACTUAL_HOURS] => 20
[PROJECTED_HOURS] => 0
)
[AUG-2015] => Array
(
[SITE_STATUS] => Offshore
[ACTUAL_HOURS] => 20
[PROJECTED_HOURS] => 0
)
)
)
$project_months output
Array
(
[0] => JUL-2015
[1] => AUG-2015
)
Looping the data like below gives summation but not for User 1
foreach ($user_array as $user_name => $user_data) {
foreach ($project_months as $month) {
}
}
How do I show summation of ACTUAL_HOURS or PROJECTED_HOURS for different resource month wise as shown above ?
You can simply use two foreach loops.
$hoursInMonth = array();
foreach ($users as $user)
{
foreach ($user as $month => $userData) {
$hoursInMonth[$month] += $userData['ACTUAL_HOURS'];
}
}
Considering the $users variable is the array from the question, this yields the following result:
Array
(
[JUL-2015] => 30
[AUG-2015] => 100
)
You could wrap it in a function, so you can easily switch between the desired index.
/**
* #param array $inputArray The input array
* #param string $typeOfHours The desired index
* #return array
*/
function calculateHoursInMonths(array $inputArray, $typeOfHours)
{
$hoursInMonth = array();
foreach ($inputArray as $user)
{
foreach ($user as $month => $userData) {
$hoursInMonth[$month] += $userData[$typeOfHours];
}
}
return $hoursInMonth;
}
Note, this does not take in consideration the Offshore/Onshore state. You can add that by adding a simple if.
You are doing it wrong. There is no need for two nested foreach loops. You just need a for loop to loop through project months and a foreach loop to loop through users array.
You did not shared the array in php code, but I assume you are array is as below:
$array = array(
'User 1' => array(
'JUL-2015' => array(
'SITES_STATUS' => 'Offshore',
'ACTUAL_HOURS' => 10,
'PROJECTED_HOURS' => 20
),
'AUG-2015' => array(
'SITES_STATUS' => 'Offshore',
'ACTUAL_HOURS' => 80,
'PROJECTED_HOURS' => 88
),
),
'User 2' => array(
'JUL-2015' => array(
'SITES_STATUS' => 'Offshore',
'ACTUAL_HOURS' => 20,
'PROJECTED_HOURS' => 0
),
'AUG-2015' => array(
'SITES_STATUS' => 'Offshore',
'ACTUAL_HOURS' => 20,
'PROJECTED_HOURS' => 0
),
),
);
And months are below:
$project_months = array('JUL-2015', 'AUG-2015');
Now to calculate total actual hours for all users for each month, you will need loops like below:
for ($i=0; $i < count($project_months); $i++) {
$totalActualHours = 0;
foreach($array AS $ar) {
$totalActualHours += $ar[$project_months[$i]]['ACTUAL_HOURS'];
}
echo $project_months[$i].': '.$totalActualHours.'<br>';
}
The output of this code when run for ACTUAL_HOURS:
JUL-2015: 30
AUG-2015: 100
Hope this will help.
I have an array in PHP of this type, resulting from a particular query on a db.
$output = Array
(
[0] => Array
(
'price' => 100
'date' => '2015-07-28'
'total' => 200
'qty' => 2
)
[1] => Array
(
'price' => 80
'date' => '2015-07-28'
'total' => 240
'qty' => 3
)
[2] => Array
(
'price' => 100
'date' => '2015-07-29'
'total' => 300
'qty' => 3
)
[3] => Array
(
'price' => 90
'date' => '2015-07-28'
'total' => 90
'qty' => 1
)
)
I'm trying to sum total and qty based on price key values, obtaining an array that will look like this:
$grouped = Array
(
[0] => Array
(
[price] => 100
[sumtotal] => 500
[sumqty] => 5
)
[1] => Array
(
[price] => 80
[sumtotal] => 240
[sumqty] => 3
)
[2] => Array
(
[price] => 90
[sumtotal] => 90
[sumqty] => 1
)
)
Still cannot find a way to get around this.
Try using simple foreach loop as
$result = array();
foreach ($output as $key => $value) {
$hash = $value['price'];
if (isset($result[$hash])) {
$result[$hash]['price'] = $value['price'];
$result[$hash]['sumtotal'] += $value['total'];
$result[$hash]['sumqty'] += $value['qty'];
} else {
$result[$hash]['price'] = $value['price'];
$result[$hash]['sumtotal'] = $value['total'];
$result[$hash]['sumqty'] = $value['qty'];
}
}
print_r(array_values($result));
Demo
I don't understand, it's the same array without the date.. ?
Edit :
Ok try this
$temp= array();
for($i=0; $i<sizeof($outpout);$i++)
{
if(!isset($temp[$i]))
$temp[$i]=array();
$temp[$i][$outpout[$i]['price']]+=$outpout[$i]['qty']];
}
$res=array();
$count=0;
foreach($temp as $key => $value)
{
$res[$count]['price']=$key;
$res[$count]['qty']=$value;
$res[$count]['total']=$key*$value;
$count++;
}
Okay, here's a simple complete code to solve your problem.
$output=array();//this is your array
$price_index=array();
$final_array=array();
foreach($output as $key=>$value)
{
//first check if price is already in $price_index
if(!isset($price_index[$value["price"]]))
{
$price_index[$value["price"]]=sizeof($price_index);
}
$final_index=$price_index[$value["price"]];
if(isset($final_array[$final_index]))
{
$final_array[$final_index]["total"]+=$value["total"];
$final_array[$final_index]["qty"]+=$value["qty"];
}
else
{
$final_array[$final_index]["total"]=$value["total"];
$final_array[$final_index]["qty"]=$value["qty"];
$final_array[$final_index]["price"]=$value["price"];
}
}
//display our final array
print_r($final_array);
What I did:
iterate through your array
check if the current price has been added to $final_array before, by creating $price_index array that contains price as key and the value is the index of $output array on the first time the price occurred.
now if the price occur again, the $price_index[current price] will be detected that it is already been set before, then we will use the value as the index of our $final_array and add the current total and qty to existing.
then display the array (optional).
Hope it helps. Please don't just copy my code, analyze and understand it mate :)
I i'm developing php application. I have used Google Chart API for display charts.
I have select and returned necessary data for chart.
I got following array as my output.
print_r($output);
//Out put
Array
(
[0] => Array
(
[month] => April
[sec_id] => 2
[sec_name] => Commerce
[count] => 1
)
[1] => Array
(
[month] => June
[sec_id] => 2
[sec_name] => Commerce
[count] => 3
)
[2] => Array
(
[month] => July
[sec_id] => 2
[sec_name] => Commerce
[count] => 1
)
[3] => Array
(
[month] => August
[sec_id] => 4
[sec_name] => Science
[count] => 3
)
[4] => Array
(
[month] => August
[sec_id] => 3
[sec_name] => Maths
[count] => 2
)
[5] => Array
(
[month] => August
[sec_id] => 1
[sec_name] => Art
[count] => 2
)
[6] => Array
(
[month] => August
[sec_id] => 2
[sec_name] => Commerce
[count] => 2
)
)
print_r(json_encode($output)); // return above array as output
I request above data using ajax ( data type is JSON)
I want to return data as bellow to generate google chart.
[
['Month', 'Art', 'Commerce', 'Maths', 'Sience'],
['April', '', 2, '', ''],
['June', '', 3, '', ''],
['July', '', 1, '', ''],
['August', 2, 2, 3, 3]
]
I tried this this code
$output = array();
$output[0] = array('Month', 'Art', 'Commerce', 'Maths', 'Science');
foreach($records as $key=> $record){
$art =''; $commerce =''; $maths=''; $science='';
if($record['sec_id'] == 1){
$art = $record['count'];
}else if($record['sec_id'] == 2){
$commerce = $record['count'];
}else if($record['sec_id'] == 3){
$maths = $record['count'];
}else if($record['sec_id'] == 4){
$science = $record['count'];
}
$output[++$key] = array(0 => $record['month'], 1 => $art, 2 => $commerce, 3 => $maths, 4 => $science);
}
function super_unique($array){
$result = array_map("unserialize", array_unique(array_map("serialize", $array)));
foreach ($result as $key => $value){
if ( is_array($value)){
$result[$key] = super_unique($value);
}
}
return $result;
}
$output = super_unique($output);
Out put was
[["Month","Art","Commerce","Maths","Science"],["April","","1"],["June","","3"],["July","","1"],{"0":"August","1":"","4":"3"},{"0":"August","1":"","3":"2"},["August","2",""],["August","","2"]]
This is pretty straightforward to loop through and reorganize, particularly since your sec_ids match up nicely with the array indices.
Example:
$temp = array();
$output = array(
array('Month', 'Art', 'Commerce', 'Maths', 'Science')
);
foreach ($records as $record) {
$month = $record["month"];
$sec_id = $record["sec_id"];
$count = $record["count"];
if (!isset($temp[$month])) {
$temp[$month] = array_fill(0, 5, '');
}
$temp[$month][0] = $month;
$temp[$month][$sec_id] += $count;
}
$output = array_merge($output, array_values($temp));
echo json_encode($output);
Output:
[["Month","Art","Commerce","Maths","Science"],["April","",2,"",""],["June","",3,"",""],["July","",1,"",""],["August",2,2,2,3]]
Let's rethink your algorithm. As you go through each element in records, we need to ask two things: what data are we pulling out and what do we want to do with it?
The first question is simple: we're just pulling out the value 'count'.
The second question is going to determine our algorithm. What we want to do is take that 'count' value, and stick it a particular spot in our ourpur array.
Looking at the output array as a table, we can see that the desired position of 'count' is determined by the 'month' field (which determines the row) and by the 'sec_id'/'sec_name' fields (which determine the column). So what you want your loop to look like is this...
foreach($records as $record)
{
$output[$record['month']][$record['sec_id']] = $record['count']
}
The first caveat to this is that for each unique month, you do still need to create and initialize the sub-array, and you must do it only once. So, the loop becomes.
foreach($records as $record)
{
if(!is_array($output[$record['month']]))
$output[$record['month']] = array(0 => $record['month'], 1 => '', 2 => '', 3 => '', 4 => '');
$output[$record['month']][$record['sec_id']] = $record['count']
}
Finally, we used the actual month name as the keys in the top-level array. To comply with the numeric-only keys specified in your desired output, we can ditch those keys with the following piece of code.
$output = array_values($output)
If I'm right in thinking you were trying to use super_unique() to combine rows with the same month, that's not what it was doing at all. Firstly, array_unique() doesn't combine rows, it eliminates duplicates. Since you were comparing serialized rows, rather than just looking at the month field, none of your rows were duplicates, so that function was doing nothing. Furthermore, since several of your array fields were set to '', the serialize/unserialize process was actually causing those fields to get dropped, which is why you were ending up with sub-arrays of less than five elements, and with associative keys.