Comparing multiple different dates and getting the average in PHP - php

I use a function called count_days($date1,$date2) that counts the number of days between two dates. But, my question is: the dates come from the DB, in an array like:
Array (
[imac] => Array (
[0] => 2002-10-10
[1] => 2003-11-22
[3] => 2004-11-10
)
[iphone] => Array (
[0] => 2007-09-11
[1] => 2008-05-12
[2] => 2009-06-14
[3] => 2010-06-05
)
)
As you can see the products may have a different number of subarrays. I want to count the days between the first and the next date (and so on!) and then get the average of days.

The DateInterval class is great for this kind of date arithmetic. You can use DateTime::add, DateTime::subtract and DateTime::diff to work with them.
<?php
$types = array(
'imac' => array ('2002-10-10', '2003-11-22', '2004-11-10'),
'iphone' => array ( '2007-09-11', '2008-05-12', '2009-06-14', '2010-06-05'),
);
$typeIntervals = array();
$typeAverage = array();
foreach ($types as $type=>$dates) {
$last = null;
$typeIntervals[$type] = array();
foreach ($dates as $date) {
$current = new DateTime($date);
if ($last) {
$interval = $current->diff($last);
$typeIntervals[$type][] = $interval->days;
}
$last = $current;
}
$typeAverage[$type] = array_sum($typeIntervals[$type]) / count($typeIntervals[$type]);
}
print_r(typeIntervals);
print_r($typeAverage);
This will output:
Array (
[imac] => Array (
[0] => 408
[1] => 354
)
[iphone] => Array (
[0] => 244
[1] => 398
[2] => 356
)
)
Array (
[imac] => 381
[iphone] => 332.66666666667
)

try smth like this ( not tested )
$lastDate = $dbArray[0][0];
$daysArray = array();
foreach ( $dbArray as $value )
{
if ( is_array($value) )
{
foreach ( $value as $v )
{
$daysArray[] = count_days($lastDate, $v);
$lastDate = $v;
}
} else {
//not an array check if it's a date and test it here
}
}
$average = array_sum($daysArray)/count($daysArray);

Related

Creating an array from a string issue

I have a function that creates a multi-dimensional array from a string. Here's how the output looks like for each string:
Strings:
app.name.version
app.vendor
NOTE: These are strings that are being retrieved from a database
Output:
['app']['name']['version']
['app']['vendor']
and I assign them values accordingly. The problem arises when I include numbers in the string representing an index number of a sub array. Here's an example:
shifts.breaks.unpaid.0.description
shifts.breaks.unpaid.0.duration
shifts.breaks.unpaid.1.description
shifts.breaks.unpaid.1.duration
with output:
Array
(
[unpaid] => Array
(
[0] => Array
(
[description] => Lunch
)
[1] => Array
(
[duration] => 30
)
[3] => Array
(
[description] => Lunch 2
)
[4] => Array
(
[duration] => 30
)
)
)
Where it should normally look like:
Array
(
[unpaid] => Array
(
[0] => Array
(
[description] => Lunch
[duration] => 30
)
[1] => Array
(
[description] => Lunch 2
[duration] => 30
)
)
)
The only thing that remedies this is if I replace the numbers with anything but numerical values like the following:
shifts.breaks.unpaid.b0.description
shifts.breaks.unpaid.b0.duration
shifts.breaks.unpaid.b1.description
shifts.breaks.unpaid.b1.duration
Array
(
[unpaid] => Array
(
[b0] => Array
(
[description] => Lunch
[duration] => 30
)
[b1] => Array
(
[description] => Lunch 2
[duration] => 30
)
)
)
Here's the function that creates the arrays:
function toArray($keys, $value){
$array = array();
$ref = &$array;
while(count($keys) > 0){
$n = array_shift($keys);
if(!is_array($ref))
$ref = array();
$ref = &$ref[$n];
}
$ref = $value;
return $array;
}
Where $keys contains $keys = explode('.', "my.testing.string"); and here's the example I've been working with:
$strings = array (
"app.names.0.first"=> "Samuel",
"app.names.0.last"=> "Smith",
"app.names.1.first" => "Mary",
"app.names.2.last" =>"Kubik"
);
$list = array();
foreach($strings as $key => $name) {
$list[] = (toArray(explode('.', $key),$name));
}
print_r(call_user_func_array('array_merge_recursive', $list));
At this point, I'm not too sure if this has something to do with array_merge_recursive. Any help in correcting this would be great!
Well one solution I found was re-writing a new array_merge_recursive function without overwriting numeric keys.
function array_merge_recursive_new() {
$arrays = func_get_args();
$base = array_shift($arrays);
foreach ($arrays as $array) {
reset($base); //important
while (list($key, $value) = #each($array)) {
if (is_array($value) && #is_array($base[$key])) {
$base[$key] = array_merge_recursive_new($base[$key], $value);
} else {
$base[$key] = $value;
}
}
}
return $base;
}
Thanks to a user on php.net. This will produce the correct output when keys are numeric.

Manipulating arrays of dates in PHP

I'm having a lot of difficulty approaching a piece of code in PHP. I have an array of dates and values, for example
dates = (2014-12-01,2014-12-02,2014-12-08,2014-12-09,2014-12-10,2014-12-11)
values = (5,3,7,8,9,2)
You'll note that 12/01 is a Monday, as is 12/08. I'd like to form 4 arrays from these two arrays:
monday = (5,7)
tuesday = (3,8)
wednesday = (0,9)
thursday = (0,2)
You'll note that the arrays are formed by grabbing the values associated with the days of the week. However, in the case that a Wednesday date exists, for example, but the prior Tuesday does not, then the array should have a "0". In other words, the 4 arrays should all be the same length.
Can anyone help me write code in PHP to achieve this? Thanks in advance!
NOTE: So far, I have only determined how to find the day of the week from a date: date('l', strtotime("2014-12-08")); I really can't figure out the general algorithm to solve this.
$dates = array( '2014-12-01','2014-12-02','2014-12-08','2014-12-09',
'2014-12-10','2014-12-11' );
$values = array( 5, 3, 7, 8, 9, 2 );
$date = strtotime(min($dates));
$stop = strtotime(max($dates));
$dates = array_flip($dates);
$out = array();
while($date <= $stop)
{
$tmp = date('Y-m-d', $date);
$out[date('l', $date)][] = isset($dates[$tmp]) && isset($values[$dates[$tmp]]) ?
$values[$dates[$tmp]] : 0;
$date = strtotime('+1 day', $date);
}
print_r($out);
Result:
Array
(
[Monday] => Array
(
[0] => 5
[1] => 7
)
[Tuesday] => Array
(
[0] => 3
[1] => 8
)
[Wednesday] => Array
(
[0] => 0
[1] => 9
)
[Thursday] => Array
(
[0] => 0
[1] => 2
)
[Friday] => Array
(
[0] => 0
)
[Saturday] => Array
(
[0] => 0
)
[Sunday] => Array
(
[0] => 0
)
)
ps: how can I get the an array of all the dates included in the "dates" array associated with only all the Mondays?
Modify the code as, for example:
$tmp = date('Y-m-d', $date);
$exists = isset($dates[$tmp]) && isset($values[$dates[$tmp]]);
$out[date('l', $date)]['numbers'][] = $exists ? $values[$dates[$tmp]] : 0;
if ($exists) $out[date('l', $date)]['dates'][] = $tmp;
$date = strtotime('+1 day', $date);
You'll get an output as (example for monday)
[Monday] => Array
(
[numbers] => Array
(
[0] => 5
[1] => 7
)
[dates] => Array
(
[0] => 2014-12-01
[1] => 2014-12-08
)
)
Might be a better way to get the 0s in there without another loop but I'm headed out:
foreach($dates as $key => $val) {
$day = date('l', strtotime($val));
$result[$day][] = $values[$key];
}
foreach($result as &$val) {
if(count($val) == 1) {
array_unshift($val, 0);
}
}
print_r($result);

Find sum of calls data from array using another array of dates

$array1 = Array (
[0] => Array
(
[day] => 2014-05-07
[total_Calls] => 1
)
[1] => Array
(
[day] => 2014-05-09
[total_Calls] => 1
)
[2] => Array
(
[day] => 2014-05-12
[total_Calls] => 1
)
[3] => Array
(
[day] => 2014-05-13
[total_Calls] => 1
)
[4] => Array
(
[day] => 2014-05-14
[total_Calls] => 2
)
[5] => Array
(
[day] => 2014-05-16
[total_Calls] => 4
)
);
$array2 = Array (
[0] => Array
(
[report_date] => 1397413800-1397932200
)
[1] => Array
(
[report_date] => 1398018600-1398537000
)
[2] => Array
(
[report_date] => 1398623400-1399141800
)
[3] => Array
(
[report_date] => 1399228200-1399746600
)
[4] => Array
(
[report_date] => 1399833000-1400351400
)
[5] => Array
(
[report_date] => 1400437800-1400956200
)
)
I want to find sum of total_Calls between dates that is in second array. I need out put like this.
I have got output using for loop but i dont want to use for loop
$array = array();
foreach ($array1 as $val) {
$temp = str_replace('-', '', $val['day']);
$array[strtotime($temp)] = $val['total_Calls'];
}
$week = array();
$sum = array();
foreach ($array as $k => $v) {
foreach ($array2 as $val) {
$temp = explode('-', $val['report_date']);
if ($k >= $temp[0] && $k <= $temp[1]) {
$sum[$val['report_date']][] = $v;
} else {
$sum[$val['report_date']][] = 0;
}
}
}
Output:
[1397413800-1397932200] => 0
[1398018600-1398537000] => 0
[1398623400-1399141800] => 0
[1399228200-1399746600] => 2
[1399833000-1400351400] => 9
[1400437800-1400956200] => 8
BRUTEFORCE!!!
<?php
$from_to = array();
foreach ($array2 as $data) {
$days = explode('-', $data['report_date']);
$from_to[] = $days;
}
$counter = array();
foreach ($array1 as $data) {
$day = new Datetime($data['day'], new Datetimezone('UTC'));
$timestamp = $day->('U');
foreach ($from_to as $range) {
if ($timestamp >= $range[0] && $timestamp <= $range[1]) {
$key = implode('-', $range);
if (!isset($counter[$key])) {
$counter[$key] = 0;
}
$counter[$key] += $data['total_Calls'];
}
}
}
print_r($counter);
There is no point in trying to avoid using loops. In fact, however you do it, you will be using loops. Either by writing one, or by using some native or custom function that will eventually use one. As that is just the way you walk through an array.
What you might want to do however is try to have as little loops as possible. And do the heavy work, such as strtotime() outside (most of) the loops, where possible.
I've given your code a walk over and compacted it. You will have your results inside $new_array.
foreach($array1 as $key=>$value)
$array1[$key]["timestamp"] = strtotime($array1[$key]["day"]);
foreach($array2 as $report) {
$new_array[$report["report_date"]] = 0;
$from_to = array_map("intval",explode("-",$report["report_date"]));
foreach($array1 as $call_day) {
$day = $call_day["timestamp"];
if ($day >= $from_to[0] && $day < $from_to[1])
$new_array[$report["report_date"]] += $call_day["total_Calls"];
}
}
DEMO

Formatting an Array in PHP

I'm pulling an array from the database and it looks like so:
Array
(
[0] => Array
(
[tracker_id] => 28
[tracking_numbers] => hdkshwuy47937892hd
)
[1] => Array
(
[tracker_id] => 28
[tracking_numbers] => 797825464411
)
)
I need to reformat it to look like this:
Array
(
[0] => Array
(
[tracker_id] => 28
[tracking_numbers] => Array
(
[0] => hdkshwuy47937892hd
[1] => 797825464411
)
)
)
I can't seem find the right search in the array or keys to create an array of numbers for the single tracker id.
Use array_column() for < php V5.5
<?php
$a=array
( array
('tracker_id' => 28,
'tracking_numbers'=> "hdkshwuy47937892hd"
),
array('tracker_id' => 28,
'tracking_numbers' => "797825464411",
) );
$a[0]['tracking_numbers']=array_column($a,"tracking_numbers");
unset($a[1]);
print_r($a);
Demo
try this
$arr_output = array();
foreach($arr_input as $arr)
{
$tracker_id = $arr['tracker_id'];
$tracking_numbers = $arr['tracking_numbers'];
$arr_output[$traker_id][] = $tracking_numbers;
}
print_r($arr_output);
UPDATE 2:
$arr_output = array();
$arr_output1 = array();
foreach($arr_input as $arr)
{
$tracker_id = $arr['tracker_id'];
$tracking_numbers = $arr['tracking_numbers'];
$arr_output[$traker_id][] = $tracking_numbers;
}
$i=0;
foreach($arr_output as $key=>$value)
{
$arr_output1[$i]['tracker_id']=$key
$arr_output1[$i]['tracking_numbers']=$value
$i+=1;
}
print_r($arr_output1);

Combination of arrays

I have tried to get the below code to work for a good couple of hours, but just don't succeed.
I have this date array:
Array ( [0] => Array ( [0] => 2007 )
[1] => Array ( [0] => 2008 )
[2] => Array ( [0] => 2009 )
...
)
and this plusMinus one:
Array ( [0] => Array ( [plus] => 2 [date] => 2007 )
[1] => Array ( [minus] => 1 [date] => 2008 )
[2] => Array ( [minus] => 1 [date] => )
[3] => Array ( [plus] => 1 [date] => 2010 [minus] => 1 )
)
I have been trying to combine them into this:
Array ( [0] => Array ( [date] => 2007 [plus]=> 2)
[1] => Array ( [date] => 2008 [minus]=> 1)
[2] => Array ( [date] => 2009 [plusMinus]=> 0)
[3] => Array ( [date] => 2010 [plus] => 1 [minus]=>1 )
...
)
So basically I want to check if a value of the date array exists in the plusMinus array. If true the date and values from the plusMinus array shall replace the entry in the date array.
If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
The way I have tried to do it is this:
foreach ($filler as $key1 => $value1)
{
foreach ($plusMinus as $key2 => $value2)
{
if ($value1['0'] !== $value2['date'])
{
$value1['plusMinus'] = '0';
$result2[$key1][] = $value1;
}
elseif ($value1['0'] == $value2['date'])
{
if (array_key_exists('plus',$value2))
{
$value1['plus'] = $value2['plus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2))
{
$value1['minus'] = $value2['minus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2) &&
array_key_exists('plus',$value2))
{
}
}
}
}
$valuesComplete = array();
foreach ($result2 as $value) {
$result2 = $value['0'];
array_push($valuesIncomplete, $result2);
}
return $valuesComplete;
Instead of the desired outcome described above I get this:
Array ( [0] => Array
( [0] => 2007 [plus] => 2 )
[1] => Array ( [0] => 2008 [plusMinus => 0 )
[2] => Array ( [0] => 2009 [plusMinus] => 0 )
[3] => Array ( [0] => 2010 [plusMinus] => 0 )
[4] => Array ( [0] => 2011 [plusMinus] => 0 )
[5] => Array ( [0] => 2012 [plusMinus] => 0 )
[6] => Array ( [0] => 2013 [plusMinus] => 0 )
)
What am I missing? Thanks for any help!
Unfortunately, because of the input data format, I can't see any way to do this that doesn't involve an O(n + m + p) operation. But no matter, you gotta do what you gotta do.
Firstly I would start by filtering the useless elements from the PlusMinus array. Since it's already fairly close to the desired output format, it makes sense to use this as the base of the result.
$temp = array();
foreach ($plusMinus as $item) {
if (!empty($item['date'])) {
$temp[$item['date']] = $item;
}
}
Notice that I used the date as the index of the temporary array we're using to build the result. This is to allow you to easily ensure that the result array is in the correct order, and to quickly check whether an item needs to be added from the Filler array.
Next, we need to add any missing elements from the Filler array:
foreach ($filler as $item) {
if (!isset($temp[$item[0]])) {
$temp[$item[0]] = array(
'date' => $item[0],
'plusMinus' => 0
);
}
}
Now all the data is in the array in the correct format, we just need to sort it:
ksort($temp);
...and get convert it back to an indexed array:
return array_values($temp);
No need for the performance killing nested loops or complex flow control.
See it working
As I understood you need to add years that not in second array but in first?
In that case you can do:
foreach ($filler as $key1 => $value1)
{
$ok = false;
foreach ($plusMinus as $key2 => $value2)
{
if($value2['date']==$value1[0])
{
$ok = true;
break;
}
}
if(!$ok)
{
$plusMinus[$value1[0]]=array('date'=>$value1[0], 'plusMinus'=>0);
}
}
<?php
$a1 = array(array( 2007 ),
array( 2008 )
);
$a2 = array(array('plus'=>1, 'date'=>2007),
array('minus'=>1,'date'=>2008),
array('plus'=>1, 'minus'=>1, 'date'=>2008)
);
$r = array();
foreach($a1 as $k1=>$d1) {
$year = $d1[0];
foreach( $a2 as $k2=>$d2 ) {
if( $d2['date'] == $year ) {
$r[$year]['date'] = $year;
if(isset($d2['plus'])) {
$r[$year]['plus'] = $d2['plus'];
}
if(isset($d2['minus'])) {
$r[$year]['minus'] = $d2['minus'];
}
}
}
}
print_r($r);
and result
Array
(
[2007] => Array
(
[date] => 2007
[plus] => 1
)
[2008] => Array
(
[date] => 2008
[minus] => 1
[plus] => 1
)
)
$ar1 = array( array(2007), array(2008), array(2009), array(2010) );
$ar2 = array(
array("date"=>2007, "plus"=>2),
array("date"=>2008, "minus"=>1),
array("date"=>"", "minus"=>1),
array("date"=>2010, "plus"=>1, "minus"=>1)
);
foreach($ar2 as $key=>$val){
if(isset($ar1[$key][0]))
$val["date"] = $ar1[$key][0];
$ar2[$key] = $val;
}
I am not sure if I understand you correctly but this works fine...
It will work only if you are sure that your both arrays "date" equals one to other..
This is what I came up with:
To not create the product of both arrays (foreach inside foreach), I first index the $plusMinus array with the date. That will allow to test quickly if a year exists or not:
$years = array_combine(array_column($plusMinus, 'date'), $plusMinus);
This uses the array_column() function of PHP 5.5, if you don't have it you can easily create it your own.
After doing that it is exactly how you wrote it in your own words:
foreach($date as &$entry)
{
list($year) = $entry;
$entry = array('date' => $year);
// check if a value of the date array exists in the plusMinus array.
if (isset($years[$year])) {
// If true the date and values from the plusMinus array shall replace the entry in the date array
$entry += $years[$year];
} else {
// If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
$entry += array('plusMinus' => 0);
}
}
unset($entry);
See it i action.
This will work just fine.
I did not at all understand your question, but if i got it this is the way:
First make your $datearray more understandable like this:
$dateArray = array(2007,2008,2009,2010);
$plusMinus = array(
array( 'plus' => 2 ,'date' => 2007),
array( 'minus' => 1 ,'date' => 2008),
array ( 'minus' => 1 , 'date' => '' ),
array ( 'plus' => 1 , 'date' => 2010 , 'minus' => 1 )
);
You can make it multidimensional later;
After that:
foreach($dateArray as $k=>$v)
{
if(in_array($v,$plusMinus[$k]))
{
$filler[$k] = $plusMinus[$k];
}
else{
if(empty($plusMinus[$k]['date']))
{
$filler[$k]['date']= $v;
$filler[$k]['plusMinus'] = 0;
}
}
}
This is simple and clean, understandable way with very little code if your arrays will always have the structure you described, meaning the plusMinus values for 2007 are in the cell [0] and the 2007 in the dateArrays is also in the cell [0] like you have shown. I hope i could help.

Categories