PHP:我有一个时间范围的关联数组($k=>$v整数),我想修剪和组合重叠的时间表


PHP: I have an assoc array with time ranges ($k=>$v integers), I want to trim and combine overlapping schedules

前提:我正在一个需要PHP 5.2兼容的项目中工作,很遗憾,我不能使用PHP 5.3+ DateInterval 或其他PHP>=5.3仅限的指令。

我有一个包含以$k => $v范围表示的营业时间的数组,因此键是开始,值是结束,如下所示:

array( 
    09:00 => 11:30
    09:30 => 11:00
    10:00 => 12:30
    13:30 => 14:30   
)

在这个例子中,我们有前三对重叠的范围,我可以将其表示为09:00 => 12:30(意思是:在上午9点开放,在下午12点30分关闭),因为前三对的开始和结束是重叠的。

我也可以这样写数组,作为整数(或者我可以使用浮点数,例如09:30变成9.3,我认为没关系):

array( 
     900 => 1130
     930 => 1100
    1000 => 1230
    1330 => 1430   
)

如何将数组转换为:

array(
     900 => 1230
    1330 => 1430
)

我想到的想法是循环数组,使用array_slice,通过引用传递值和unset()的东西,而在它…但我不确定这是不是最好的主意,或者我只是把它复杂化了。

这个问题有很多解决方案;我:

http://phpfiddle.org/main/code/batv-hzqw

希望它足够清楚,并满足您所制定的标准——如果不是,请告诉我:)

进行这种类型的重叠检查的一种方法是使用以下算法:测试两个整数范围重叠的最有效方法是什么?

伪代码
  1. 循环你所有的时间范围,如果它们重叠,把它们放在同一个桶里。

PHP示例

:

<?php
$times = array( 
     900 => 1130,
     930 => 1100,
    1000 => 1230,
    1330 => 1430,
     845 => 900,
    1330 => 1700,
     845 => 1000   
);

function reduceOverlap($times) {
    $reduced = array();
    //Put the first entry into our final bucket
    $reduced[array_keys($times)[0]] = $times[array_keys($times)[0]];
    foreach ($times as $start => $end) {
        // Trip this flag if a new bucket does not need to be created
        $foundOverlap = false;
        // Check if this time can go in one of our buckets
        foreach ($reduced as $reducedStart => $reducedEnd) {
            // Truthy check for overlap of time range with bucket range
            if ($start <= $reducedEnd && $end >= $reducedStart) {
                // Use this for start key incase it gets changed
                $startKey = $reducedStart;
                // Was the start less than the bucket's start? 
                // If yes update bucket's start time
                if ($start < $reducedStart) {
                    unset($reduced[$reducedStart]);
                    $reduced[$start] = $reducedEnd;
                    $startKey = $start;
                }
                // Was the end greater than the bucket's end?
                // If yes update bucket's end time
                if ($end > $reducedEnd) {
                    $reduced[$startKey] = $end;
                }
                $foundOverlap = true;
            }
        }
        // There was no overlap, create a new bucket
        if (!$foundOverlap) {
            $reduced[$start] = $end;
        }
    }
    return $reduced;
}
var_dump(reduceOverlap($times));
输出:

array(2) {
  [1330]=>
  int(1700)
  [845]=>
  int(1230)
}