给定一个包含如下时隙的PHP关联数组:
$timeSlots = Array (
"12:00:00" => "12:05:00",
"12:10:00" => "12:15:00",
"16:40:00" => "16:45:00",
"16:50:00" => "17:00:00"
);
假设所有间隔都不重叠,并且开始时间都按升序排序。
我想要一个函数返回当前时间和下一个可用时隙的可用时隙。我假设所有的插槽都是免费的 即,现在说时间是16:42,然后我想返回第3个时段 - “16:40:00”=> “16:45:00”并以“16:50:00”=>返回下一个广告位“17时00分○○秒”即可。
我尝试的是这样的,使用线性搜索来获取时间间隔:
function searchTimeSlots ($currentTime) {
global $timeSlots;
$timeSlot = null;
$getNext = false;
// get the current time slot and next available one or just next available one if there's no current time slot
foreach ($timeSlots as $fromTime => $toTime) {
if ($getNext) {
$timeSlot['next'] = Array (
"start" => $fromTime,
"finish" => $toTime
);
break;
}
if (($currentTime >= $fromTime) && ($currentTime < $toTime)) {
$timeSlot = Array (
"current" => Array (
"start" => $fromTime,
"finish" => $toTime
)
);
$getNext = true;
}else if ($currentTime < $fromTime) {
$timeSlot = Array (
"next" => Array (
"start" => $fromTime,
"finish" => $toTime
)
);
break;
}
}
// if there's no current or next slot available send the first available slot
if ($timeSlot == null) {
foreach ($timeSlots as $fromTime => $toTime) {
$timeSlot = Array (
"next" => Array (
"start" => $fromTime,
"finish" => $toTime
)
);
break;
}
}
return $timeSlot;
}
这将返回数组
Array ( [current] => Array ( [start] => 16:40:00 [end] => 16:45:00 ) [next] => Array ( [start] => 16:50:00 [end] => 17:00:00 ) )
我想知道是否有更好的方法来获取此数组。任何帮助将不胜感激。
答案 0 :(得分:0)
希望您正在寻找以下内容:
<?php
$timeSlots = Array (
"12:00:00" => "12:05:00",
"12:10:00" => "12:15:00",
"16:40:00" => "16:45:00",
"16:50:00" => "17:00:00"
);
function getTimeSlots ($timeSlots,$currentTime) {
$new_time_slot = [];
array_walk($timeSlots,function($end,$start) use($currentTime,&$new_time_slot){
if($currentTime<=strtotime($start)){
$new_time_slot[$start] = $end;
}
});
return $new_time_slot;
}
$currentTime = strtotime("12:14:00"); // or time() to get current time
$new_time_slot = getTimeSlots($timeSlots,$currentTime);
print_r($new_time_slot);
答案 1 :(得分:0)
给出已排序的非重叠时间列表($timeSlots
)
给定特定时间($ timeNow)
快速搜索时间列表并返回以下内容:
1)如果timeNow
在timeSlot
范围内,则返回timeSlot
2)如果在&#39; timeNow&#39;之后有一个有效的timeSlot
可用。然后返回下一个有效的timeSlot
。
查询需要高效,因为可以重复调用不同的特定时间(&#39; timeNow&#39;)
思想
由于timeslots
是一个固定的数字,有序和非有限,因此找到所需数字的最快方法是使用二进制搜索&#39;在阵列上。
要求测试“时间点”&#39;在timeSlot
的持续时间范围内不是问题。
识别下一个有效timeSlot
的要求意味着只有“真实时间”和“真实时间”。不能在&time;时间&#39;阵列。 &#39;差距&#39;在&#39; real timeSlots&#39;之间需要记录以便“二进制搜索”。会正常工作。即timeNow
将永远是“真实时间”和“真实时间”。或者“差距”紧接在下一个实时时间之前#39;
实施
1)&#39; timeSlot&#39;的有序数组。 ($startTimes
)其中每个&#39; timeSlot&#39;具有以下属性:
我决定将所有代码放在一个类(TimeRanges
)中,因为要从输入到内部格式进行转换。此外,输入timeSlots只需要在startTimes
转换一次。
输出
Demonstration (with test data) at eval.in
TimeRanges
class TimeRanges {
/**
* need this for binary search
*/
private $startTimes = array();
private $lastSlotIdx = 0;
// outputs so you don't need to run the search again
private $timeNow = 0;
private $outSlots = array();
private $dateWhen = null; // used to convert seconds to different formats
/**
* @param array The timeSlots that will be searched
*/
public function __construct(array $timeSlots) {
$this->buildAllstartTimes($timeSlots);
$this->dateWhen = new \DateTime();
}
/**
* Create a list of real and 'virtual' timeslots.
* i.e. All gaps between the real timeslots we treat as a timeslot
* when searching for a matching timeslot
*/
protected function buildAllStartTimes($timeSlots) {
$this->startTimes = array();
$iter = new ArrayIterator($timeSlots);
$prvEndTime = PHP_INT_MAX; // needed to identify 'gaps'
while ($iter->valid()) {
$curStartTime = $this->asSeconds($iter->key()); // seconds
$curEndTime = $this->asSeconds($iter->current()); // so is easy to check
if ($curStartTime > $prvEndTime) { // make a 'gap' timeslot
$this->startTimes[] = ['s' => $prvEndTime + 1,
'e' => $curStartTime,
'real' => false];
$prvEndTime = $curStartTime;
} else { // is real
$this->startTimes[] = ['s' => $curStartTime,
'e' => $curEndTime,
'real' => true];
$prvEndTime = $curEndTime;
$iter->next();
}
}
$this->lastSlotIdx = count($this->startTimes) - 1;
}
/**
* Search the array using a modifield binary search
*
* This can return zero, one or two 'real' timeslots:
*
* o timeNow before first timeslot -- return first timeslot
* o timeNow after last timeslot -- return empty array
* o timeNow on a 'gap' -- return one timeslot (the next one)
*
* @param string current time
*/
public function findTimeSlots($timeNow) {
$this->timeNow = $this->asSeconds($timeNow);
$startSlotIdx = $this->searchStartTimes($this->timeNow, 0, $this->lastSlotIdx);
$returnedSlots = 1;
if ($startSlotIdx > $this->lastSlotIdx ) {
$returnedSlots = 0;
} elseif ( isset($this->startTimes[$startSlotIdx])
&& $this->startTimes[$startSlotIdx]['real']) {
$returnedSlots = 2;
}
$out = array(); // need current and next real timeslots in the array
for ($numSlots = $returnedSlots; $numSlots > 0; $numSlots--, $startSlotIdx++) {
$startSlotIdx = $this->getNextRealTimeSlotIdx($startSlotIdx);
if ( isset($this->startTimes[$startSlotIdx])
&& $this->startTimes[$startSlotIdx]['real']) { // valid timeslot
$out[] = ['s' => $this->asHHMMSS($this->startTimes[$startSlotIdx]['s']),
'e' => $this->asHHMMSS($this->startTimes[$startSlotIdx]['e'])];
}
}
$this->outSlots = $out;
return $out;
}
/**
* find required timeslot using a nodified binary search on $startTimes
*
* This can be used to find the next valid timeslot so we need to return
* various conditions:
*
* o -1 -- timeNow is before the first valid timeslot
* o 0 .. n -- timeslot (real or not) that is within the array
* o PHP_MAX_INT -- timeNow is after the end of the array
*
* @param string current time
* @param integer startRange to timeslots to search
* @param integer endRange of timeslots to search
* @return integer index
*/
protected function searchStartTimes($timeNow, $rangeStart, $rangeEnd) {
// \Kint::dump(__METHOD__.__LINE__, $timeNow, $this->asHHMMSS($timeNow), $rangeStart, $rangeEnd);
while ($rangeStart <= $rangeEnd) {
// mid point of the range
$currentIdx = (int) ($rangeStart + ($rangeEnd - $rangeStart) / 2); // see floor()
if ($timeNow >= $this->startTimes[$currentIdx]['s']) { // possible start key
// check is within the end of the timeSlot
if ($timeNow <= $this->startTimes[$currentIdx]['e']) { // found it
return $currentIdx; // finished
}
// not found correct time slot yet - search upper range
if ($timeNow >= $this->startTimes[$currentIdx]['s']) {
$rangeStart = $currentIdx + 1;
}
} else {
// timeNow is after current StartTime - go find a lower range
$rangeEnd = $currentIdx - 1;
}
} // endwhile
return $rangeEnd < 0 ? -1 : PHP_INT_MAX; // not in the array
}
/**
* Find the next 'real' timeSlot in the array
*
* The input can be:
* o Before the first time in the array
* o On a timeSlot in the array
* o On a 'gap' in the array
*
* PHP_INT_MAX indicates not in the array.
*
* @param integer Current timeslot position
* @return integer
*/
protected function getNextRealTimeSlotIdx($startSlotIdx) {
while ( $startSlotIdx < 0
|| ( isset($this->startTimes[$startSlotIdx])
&& !$this->startTimes[$startSlotIdx]['real'])) {
$startSlotIdx++;
}
if (!isset($this->startTimes[$startSlotIdx])) {
$startSlotIdx = PHP_INT_MAX;
}
return $startSlotIdx;
}
/**
* get any information from the class. It is maintained correctly
*/
public function __get($name) {
if (property_exists($this, $name)) {
return $this->$name;
}
return null;
}
public function asSeconds($hhmmss) {
return strtotime($hhmmss);
}
public function asHHMMSS($seconds) {
$this->dateWhen->setTimestamp($seconds);
return $this->dateWhen->format('H:i:s');
}
} // end class
测试数据和查找许多不同的&time; <#em>
输入实时时间段:
$timeSlots = Array (
"12:00:00" => "12:05:00",
"12:10:00" => "12:15:00",
"16:40:00" => "16:45:00",
"16:50:00" => "17:00:00"
);
示例&#39; timeNow&#39;列表:
$testData = ['11:59:00', '12:01:00', '15:00:00', '16:51:00', '17:01:00'];
创建类并执行查找:
$timeRanges = new TimeRanges($timeSlots);
// run the search
$timeRanges = new TimeRanges($timeSlots);
$foundSlots = array();
foreach ($testData as $timeNow) { // process all the test data times...
$foundSlots[] = $timeRanges->findTimeSlots($timeNow);
}
输出结果
testTime: 11:59:00
Array
(
[0] => Array
(
[s] => 12:00:00
[e] => 12:05:00
)
)
testTime: 12:01:00
Array
(
[0] => Array
(
[s] => 12:00:00
[e] => 12:05:00
)
[1] => Array
(
[s] => 12:10:00
[e] => 12:15:00
)
)
testTime: 15:00:00
Array
(
[0] => Array
(
[s] => 16:40:00
[e] => 16:45:00
)
)
testTime: 16:51:00
Array
(
[0] => Array
(
[s] => 16:50:00
[e] => 17:00:00
)
)
testTime: 17:01:00
Array
(
)