[英]Determining overlapping time ranges based on day of the week
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. [3] => 1 表示存在时间重叠冲突。
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).它保留了 $events 数组的原始顺序,因为文本日期排序不好(星期五会在星期三之前等)。 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演示: https : //3v4l.org/JeGdR
Algorithm:算法:
To find out collisions between times, we first make an array of size 86400 for each day.为了找出时间之间的冲突,我们首先为每天制作一个大小为86400的数组。 86400 because it is no. 86400因为它不是。 of seconds (24*60*60)
for a day(like Monday or Tuesday etc).一天(如星期一或星期二等)的秒数(24*60*60)
)。
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(
...
),
...
)
array("Monday", '19:10:00', '19:40:00', 0)
and end time is 2 nd position in array("Monday", '19:10:00', '19:40:00', 0)
.这里开始时间是在第1个位置(基于0的索引) array("Monday", '19:10:00', '19:40:00', 0)
和结束时间是2次在位置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. &
用于将更新与实际的$events
数组同步,因此它是通过引用传递的。
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
.在上图中,对于每个日期的开始时间,我们将+1
和-1
添加到它的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
.这意味着,当我们从 1 迭代到 11 并继续求和值时,如果我们发现任何日期的开始时间或结束时间的sum > 1
,我们就会发现存在冲突,我们需要将其值设置为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
.这里,用于此代码的空间是86400 * 7 = 604800
,这是常数空间O(1)
因为这不取决于$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
.时间复杂度再次是恒定迭代86400 * 7 = 604800
+ 通过$events
每个元素循环两次,这使得它O(n)
其中n
是$events
大小。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.