I have an array of time ranges like this:-
$events = array(
array("Monday", '19:00:00', '19:30:00', 0),
array("Monday", '19:10:00', '19:40:00', 0),
array("Tuesday", '19:10:00', '19:40:00', 0),
array("Wednesday", '19:10:00', '19:40:00', 0),
array("Monday", '19:30:00', '19:50:00', 0),
);
I am using bubble sort on the array:-
for($i = 0; $i < (count($events) - 1); $i++)
{
for($j = 1; $j < (count($events) - i - 1); $j++)
{
if($events[$i][0] < $events[$j][0])
{
if ($events[$j] > $events[($j + 1)])
{
$swap = $events[$j];
$events[$j] = $events[($j + 1)];
$events[($j + 1)] = $swap;
}
}
}
}
The result comes like this:-
Array (
[0] => Array (
[0] => Monday
[1] => 19:00:00
[2] => 19:30:00
[3] => 0)
[1] => Array (
[0] => Monday
[1] => 19:10:00
[2] => 19:40:00
[3] => 0)
[2] => Array (
[0] => Monday
[1] => 19:30:00
[2] => 19:50:00
[3] => 0)
[3] => Array (
[0] => Tuesday
[1] => 19:10:00
[2] => 19:40:00
[3] => 0)
[4] => Array (
[0] => Wednesday
[1] => 19:10:00
[2] => 19:40:00
[3] => 0)
)
Now I need to strike out those time ranges which overlap on a specific day.
Like this:
Array (
[0] => Array (
[0] => Monday
[1] => 19:00:00
[2] => 19:30:00
[3] => 1)
[1] => Array (
[0] => Monday
[1] => 19:10:00
[2] => 19:40:00
[3] => 1)
[2] => Array (
[0] => Monday
[1] => 19:30:00
[2] => 19:50:00
[3] => 1)
[3] => Array (
[0] => Tuesday
[1] => 19:10:00
[2] => 19:40:00
[3] => 0)
[4] => Array (
[0] => Wednesday
[1] => 19:10:00
[2] => 19:40:00
[3] => 0)
)
The ones which are [3] => 1, denote there is a time overlap conflict.
How can I proceed?
I tried to use this solution, but got no luck. Besides, mine has a day of week.
I had a little play and this is what I came up with. It preserves the original order of the $events array as textual days don't sort well (Friday would come before Wednesday etc). A bit brute force, not optimised or properly tested, but hope it's useful for ideas.
foreach ($events as $event_id=>$event) {
$days[$event[0]][]=[$event_id,$event[1],$event[2]];
}
foreach ($days as $dayevents) {
if (count($dayevents)>1) {
foreach ($dayevents as $dayevent1) {
foreach ($dayevents as $dayevent2) {
if ((($dayevent1[1]>$dayevent2[1]) and ($dayevent1[1]<$dayevent2[2])) or
(($dayevent1[2]>$dayevent2[1]) and ($dayevent1[2]<$dayevent2[2]))) {
$events[$dayevent1[0]][3]=1;
$events[$dayevent2[0]][3]=1;
}
}
}
}
}
$events = array(
array("Monday", '19:00:00', '19:30:00', 0),
array("Monday", '19:10:00', '19:40:00', 0),
array("Tuesday", '19:10:00', '19:40:00', 0),
array("Wednesday", '19:10:00', '19:40:00', 0),
array("Monday", '19:30:00', '19:50:00', 0),
);
$combined = array();
// first we collect all intervals for the given day
foreach($events as $record)
{
$combined[$record[0]][] = array(
$record[1], $record[2], 0
);
}
// then for each day we look if there are overlaps
foreach($combined as $day => &$intervals)
{
$len = count($intervals);
// we compare each interval with each of the rest intervals for the same day
foreach($intervals as $i => &$interval_1)
{
// we convert the start/end times of the interval A to an integer
$begin_1 = str_replace(':','',$interval_1[0]);
$end_1 = str_replace(':','',$interval_1[1]);
for($k = $i + 1; $k < $len; $k++)
{
// we convert the start/end times of the interval B to an integer
$begin_2 = str_replace(':','',$intervals[$k][0]);
$end_2 = str_replace(':','',$intervals[$k][1]);
// we compute the overlap of the 2 intervals
$overlap = max(0,$end_1 - $begin_1 - max(0,$end_1 - $end_2) - max(0,$begin_2 - $begin_1));
if($overlap)
{
$interval_1[2]++; // we increase the counter of interval A
$intervals[$k][2]++; // we increase the counter of interval B
}
}
}
}
<?php
$events = array(
array("Monday", '19:00:00', '19:10:00'),
array("Monday", '19:05:00', '19:20:00'),
array("Tuesday", '19:10:00', '19:40:00'),
array("Wednesday", '19:10:00', '19:40:00'),
array("Monday", '19:15:00', '19:30:00'),
);
function convertToSeconds($time){
$time = explode(":",$time);
return intval($time[0]) * 3600 + intval($time[1]) * 60 + intval($time[2]);
}
$time_ranges = [];
$hold_dates = [];
for($i=0;$i<=86401;++$i){
$time_ranges[] = 0;
$hold_dates[$i] = [];
}
$time_range_for_week = [];
$week_days = ['monday' ,'tuesday','wednesday','thursday','friday','saturday','sunday'];
foreach($week_days as $day){
$time_range_for_week[$day] = [
'hold_dates' => $hold_dates,
'time_range' => $time_ranges
];
}
foreach($events as &$data){
$start_time = convertToSeconds($data[1]);
$end_time = convertToSeconds($data[2]);
$time_range_for_week[strtolower($data[0])]['hold_dates'][$start_time][] = &$data;
$time_range_for_week[strtolower($data[0])]['hold_dates'][$end_time][] = &$data;
$time_range_for_week[strtolower($data[0])]['time_range'][$start_time] += 1;
$time_range_for_week[strtolower($data[0])]['time_range'][$end_time + 1] -= 1;
}
foreach($time_range_for_week as $day_name => &$day_data){
$sum = 0;
foreach($day_data['time_range'] as $time => $value){
$sum += $value;
if($sum > 1 && count($day_data['hold_dates'][$time]) > 0){
foreach($day_data['hold_dates'][$time] as &$each_event){
$each_event[3] = 1;
}
}
}
}
print_r($events);
Demo: https://3v4l.org/JeGdR
Algorithm:
This is rather simple and efficient than basic brute force.
To find out collisions between times, we first make an array of size 86400 for each day. 86400 because it is no. of seconds(24*60*60) for a day(like Monday or Tuesday etc).
The array looks like this for a particular day(like Monday or Tuesday etc):
Structure:
Array
(
[monday] => Array
(
[hold_dates] => Array
(
[],[],[],... till 86400
),
[time_range] => Array
(
[],[],[],... till 86400
),
),
[tuesday] => Array(
...
),
...
)
In the hold_dates key for a day, we are just going to have our array values at the start time and end times positions. Here start time is the 1st position(0-based indexing) in array("Monday", '19:10:00', '19:40:00', 0) and end time is 2nd position in array("Monday", '19:10:00', '19:40:00', 0). In the code, the lines look like:
Code:
$time_range_for_week[strtolower($data[0])]['hold_dates'][$start_time][] = &$data;
$time_range_for_week[strtolower($data[0])]['hold_dates'][$end_time][] = &$data;
The & is used for syncing updates with actual $events array, so it's a pass by reference.
The time_range will just hold integer values and those integer values as explained below.
Let's consider intervals like below:
[2,7],
[4,9],
[6,10]
We have a timeline like below:
1 2 3 4 5 6 7 8 9 10 11 // these are seconds from 1 to 11
+1 -1
+1 -1
+1 -1
1 1 2 2 3 3 2 2 1 0
In the above diagram, for each date's start time, we add +1, and -1 to it's end time + 1. This means that, when we iterate from 1 to 11 and keep summing values, if we find any date's start time or end time having a sum > 1, we found there is a collision and we need to set it's value to 1.
We do the same in the above code. Here, the space used for this code is 86400 * 7 = 604800, which is constant space O(1) since this does not depend upon size of $events.
Time complexity is again the constant iterations 86400 * 7 = 604800 + looping twice through each element in $events, which makes it O(n) where n is size of $events.
Related
I have an array with the hours of production like this (the number of array is not fixed, somethimes we can have production in January, not in february, and restart in March etc...) :
Array
(
[0] => Array
(
[Month] => 8
[HoursProd] => 181.37
)
[1] => Array
(
[Month] => 9
[HoursProd] => 699.35
)
[2] => Array
(
[Month] => 10
[HoursProd] => 500.25
)
[3] => Array
(
[Month] => 11
[HoursProd] => 350.61
)
)
I want to divide the hours in my array by the number of hours in the month. Get the month key (number of th month), calculate the number of hours in this month, and divide my Hours value by this number.
For the number of hours, i write this code for try to have the total of hours in a month.:
$m = 1;
$a = date('m');
$y = date("y");
$result2 = array();
for($m; $m <= 12; $m++){
$d=cal_days_in_month(CAL_GREGORIAN,$m,$y);
$result2[]["HoursTotalMonth"] = $d * 24;
$result2[]["Month"] = $m;
$t = $d * 24;
//To simplify the problem, i try to convert Hours of the month in the same array of production, and wheen the value of month is the same, divise value hours prod by value of hours total month
$test[] = array("Month" => $m, "HoursTotalMonth" => $t);
};
I try lot of things whithout success. The goal being at the end to be able to create a Json file to create a chart with ChartJS, The goal being at the end to be able to create a Json file to create a graph with ChartJS, with the production hour / hour ratio of the month in percentage. I succeed with a simple array but not with an associative multidimentional array.
Ex : [Month] => 8
[RatioHoursProdOnHoursTotalMonth] => 24.37 // (181.37 / (31j*24h))
I want this array :
Array
(
[0] => Array
(
[Month] => 8
[RatioHoursProdOnHoursTotalMonth] => 24.37
)
[1] => Array
(
[Month] => 9
[RatioHoursProdOnHoursTotalMonth] => 97.13
)
[2] => Array
(
[Month] => 10
[RatioHoursProdOnHoursTotalMonth] => 67.23
)
[3] => Array
(
[Month] => 11
[RatioHoursProdOnHoursTotalMonth] => 48.69
)
)
To be able to use the Json encoder, like this one:
[{"Month":8,"RatioHoursProdOnHoursTotalMonth":24.37},{"Month":9,"RatioHoursProdOnHoursTotalMonth":97.13},{"Month":10,"RatioHoursProdOnHoursTotalMonth":67.23},{"Month":11,"RatioHoursProdOnHoursTotalMonth":48.69}]
Is it what you expect as output ?
$a = date('m');
$y = date("y");
$result = array();
$data = array(100,60,75,90,58,98,105,85,74,685,700,550);
for ($m = 1; $m <= 12; $m++){
$d = cal_days_in_month(CAL_GREGORIAN, $m, $y);
$result[] = [
"Heure" => $d * 24,
"Mois" => $m,
"ratio" => $data[$m - 1] * 100 / ($d * 24),
];
};
print_r($result);
With the help of #Melvyn Marigny, the code below make the output i want.
$m = 1;
$a = date('m');
$y = date("y");
$nb = count($result);
for ($m = 1; $m <= $nb; $m++){
$d = cal_days_in_month(CAL_GREGORIAN, $m, $y);
$result3[] = [
"Mois" => $result[$m - 1]["Mois"],
"HeureProd" => $result[$m - 1]["Heure"],
"HeureMois" => $d * 24,
"ratio" => $result[$m - 1]["Heure"] / ($d * 24),
];
}
print_r($result3);
Array
(
[0] => Array
(
[Mois] => 8
[HeureProd] => 181.37
[HeureMois] => 744
[ratio] => 0.24377688172043
)
[1] => Array
(
[Mois] => 9
[HeureProd] => 753.39
[HeureMois] => 696
[ratio] => 1.0824568965517
)
[2] => Array
(
[Mois] => 10
[HeureProd] => 1292.25
[HeureMois] => 744
[ratio] => 1.7368951612903
)
[3] => Array
(
[Mois] => 11
[HeureProd] => 376.11
[HeureMois] => 720
[ratio] => 0.522375
)
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!
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);
Is there a way that I can approach this to some other solution?
I have 7 arrays (monday, tuesday, wednesday, thrusday, friday, saturday, sunday).
Each one of this arrays have arrays inside of them. and I need to check if all days have the same amount of data.
So im comparinng something like this:
if(count($monday) == count($tuesday)){
if(count($tuesday) == count($wednesday)){
if(count($wednesday) == count($thursday)){
if(count($thursday) == count($fruday)){
if(count($fruday) == count($saturday)){
if(count($saturday) == count($sunday)){
echo 'ok whole week is the same';
}
else{
//print sunday
//compare the rest which could print and keep comparing rest of the days
}
}
else{
//print saturday and comapre
}
}
else{
//print friday and compare
}
}
else{
//print thurdasy and compare
}
}
else{
//print wednesday and compare
}
}
else{
//print tuesday and compare
}
}
else{
//print monday
//compare rest of the days
}
As you can see it would become a huge if statement tree, I dont have that much of experience to know any other approach to this, but id you do, please help me!
thank you!
Use $diff = array_diff($monday,$tuesday,$wednesday, etc...);
$diff will contain the differences if there are any...
$bol = 0;
if(count($monday) == count($tuesday)){
$bol = $bol+1
} else {print $moday;}
//continue for all weeks
if ($bol ==6) {
echo 'ok whole week is the same';
}
How about this:
<?php
echo "<pre>";
$days = array('sunday' => array(1,2), 'saturday' => array(1,2,3), 'friday' => array(1,2,3,5), 'thursday' => array(1,2,3), 'wednesday' => array(1,2,3,4,5,6), 'tuesday' => array(1), 'monday' => array(1,2, 3,4,5,6,7,8));
//Create a count array
$count = array();
//populate count array
foreach ($days as $k => $v)
{
$count[$k] = count($v);
}
//reverse sort it
arsort($count);
//if both end of array elements are the same all are the same
if (reset ($count) == end($count))
{
echo 'ok whole week is the same';
} else {
foreach ($count as $d => $c)
{
echo $d . ": " . implode ( ", " , $days[$d] ) . "\n";
}
}
echo "</pre>";
?>
Initial array of days:
Array
(
[sunday] => Array
(
[0] => 1
[1] => 2
)
[saturday] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[friday] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 5
)
[thursday] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[wednesday] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
)
[tuesday] => Array
(
[0] => 1
)
[monday] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
)
)
and Output:
monday: 1, 2, 3, 4, 5, 6, 7, 8
wednesday: 1, 2, 3, 4, 5, 6
friday: 1, 2, 3, 5
thursday: 1, 2, 3
saturday: 1, 2, 3
sunday: 1, 2
tuesday: 1
This solution uses the fact that the two comparison variables are quite predictable (ie. a single day is compared with the very next day).
All the daily arrays are placed into a single weekly array, which is then looped over. If there is a discrepancy, the contents of the last variable are displayed and the loop continues.
If there are no discrepancies then the success message is displayed.
<?php
$bIsCorrect = true;
$weeks_array = array($monday,$tuesday,$wednesday,$thursday,$friday,$saturday,$sunday);
//Loop through weeks starting from $monday and going only to $saturday
for($i=0,$max_count=6; $i<$max_count; $i++) {
if(count($weeks_array[$i]) != count($weeks_array[$i+1])) {
$bIsCorrect = false;
$array_text = var_export($weeks_array[$i+1], true);
echo "Discrepancy : <br> $array_text";
echo "<hr>";
}
}
if($bIsCorrect) {
echo "ok whole week is the same";
}
i have below array
Array
(
[0] => Array
(
[from_time] => 15:00
[to_time] => 17:15
)
[1] => Array
(
[from_time] => 10:00
[to_time] => 12:15
)
[2] => Array
(
[from_time] => 09:00
[to_time] => 11:15
)
[3] => Array
(
[from_time] => 09:00
[to_time] => 11:15
)
[4] => Array
(
[from_time] => 14:00
[to_time] => 16:15
)
[5] => Array
(
[from_time] => 15:00
[to_time] => 17:15
)
)
i want to get common time in this array.
If i Find common time in this array my expected result should be
Array
(
[0] => Array
(
[from_time] => 10:00
[to_time] => 11:15
)
[1] => Array
(
[from_time] => 15:00
[to_time] => 16:15
)
)
I have try with below code but not getting accurate result.
foreach ($booking_time as $time1) {
foreach ($booking_time as $time2) {
{
if(($time1['from_time'] > $time2['from_time'] && $time1['from_time'] < $time2['to_time'])|| ( $time1['to_time'] > $time2['from_time'] && $time1['to_time'] < $time2['to_time'])){
echo $time1['from_time'];
echo $time1['to_time'];
}
}
}
}
Quick example (I think it can be shorter, but for quick understanding it is ok) :
$intervals = [
['from_time' => '15:00', 'to_time' => '17:15'],
['from_time' => '10:00', 'to_time' => '12:15'],
['from_time' => '09:00', 'to_time' => '11:15'],
['from_time' => '09:00', 'to_time' => '11:15'],
['from_time' => '14:00', 'to_time' => '16:15'],
['from_time' => '15:00', 'to_time' => '17:15'],
];
$overlaps = [];
foreach ($intervals as $interval) {
$key = null;
foreach ($overlaps as $_key => $_intervals) {
foreach ($_intervals as $_interval) {
if (
($_interval['from_time'] <= $interval['from_time'] && $interval['from_time'] <= $_interval['to_time'])
||
($_interval['from_time'] <= $interval['to_time'] && $interval['to_time'] <= $_interval['to_time'])
) {
$key = $_key;
break 2;
}
}
}
if (is_null($key)) {
$key = count($overlaps);
}
$overlaps[$key][] = $interval;
}
foreach ($overlaps as &$overlap) {
$from = '00:00';
$to = '23:59';
foreach ($overlap as $_interval) {
$from = max($from, $_interval['from_time']);
$to = min($to, $_interval['to_time']);
}
$overlap = ['from_time' => $from, 'to_time' => $to];
}
unset($overlap);
print_r($overlaps);
Output :
Array
(
[0] => Array
(
[from_time] => 15:00
[to_time] => 16:15
)
[1] => Array
(
[from_time] => 10:00
[to_time] => 11:15
)
)
General Overlay for comparing A and B
X) A(start) < B(start) < A(end) < B(end)
Y) B(start) < A(start) < B(end) < A(end)
(and usually full inclusions are required as well)
B(start) <= A(start) < A(end) <= B(end)
A(start) <= B(start) < B(end) <= A(end)
You actually wrote that down, but you overlooked that A and B are switching places in your source (A will be B and B A at another run -> you only need to check X or Y) and depending on which case you check you have to adjust your variable/key selection.
Additionally you are not handling inclusions well (exluding them or appropriately including them).
Simple example:
a = 10-20
b = 15-25
you would expect 15-20 as result
lets assume the run: time1 a, time2 b
$time1['to_time'] > $time2['from_time'] &&
$time1['to_time'] < $time2['to_time']
matches and prints
10-20 (time1 (a) from and to -- you wanted to print time2 from and time1 to)
another run will assign: time2 a and time1 b
$time1['from_time'] > $time2['from_time'] &&
$time1['from_time'] < $time2['to_time'])
matches and prints
15-25 (time1 (b) from and to -- you wanted to print time1 from and time2 to)
Here a working example
foreach($array as $key => $time1) {
foreach($array as $key2 => $time2) {
if (($time1["from_time"] < $time2["from_time"]) && ($time2["from_time"] < $time1["to_time"]) && ($time2["to_time"] > $time1["to_time"])) {
$overlap[] = array("from_key" => $time2["from_time"], "to_time" => $time1["to_time"]);
}
//inclusion
if (($time1["from_time"] >= $time2["from_time"]) && ($time2["to_time"] >= $time1["to_time"]) && ($key !== $key2)) {
$overlap[] = array("from_time" => $time1["from_time"], "to_time" => $time1["to_time"]);
}
}
}
Disclaimer: There are no checks for double entries. If you dont want inclusions you need a way to handle A(start) < B(start) < A(end) == B(end) etc.
you wanna increment or += [any number]
$latest = aray_pop($booking_time); // this will grab the last element from the array
for($i = 0; $i < $latest; $i += 15 // this is the number you want to increment by) {
$booking_time[$key] = $i;
}