将开放时间与开始和结束时间分组,以区分Interval

时间:2016-12-14 19:36:06

标签: php arrays time

假设您有一个这样的数组:

$timeslots[] = ['start' => '09:00:00', 'end' => '10:00:00'];
$timeslots[] = ['start' => '10:00:00', 'end' => '11:00:00'];
$timeslots[] = ['start' => '11:00:00', 'end' => '12:00:00'];
$timeslots[] = ['start' => '13:00:00', 'end' => '14:00:00'];
$timeslots[] = ['start' => '15:00:00', 'end' => '16:00:00'];
$timeslots[] = ['start' => '16:00:00', 'end' => '17:00:00'];
$timeslots[] = ['start' => '17:00:00', 'end' => '18:00:00'];

您将如何处理此数组以获得以下最终结果:

09-11,13,15-17

这个最终结果基本上代表了对可用插槽的最短可能概述以及对连续插槽进行分组(其中currentItem.EndHour == nextItem.startHour)

现在,插槽中的间隔始终相同,但间隙可以完全随机。为了说明,数组可能看起来像这样:

$timeslots[] = ['start' => '10:30:00', 'end' => '11:30:00'];
$timeslots[] = ['start' => '11:30:00', 'end' => '12:30:00'];
$timeslots[] = ['start' => '14:00:00', 'end' => '15:00:00'];
$timeslots[] = ['start' => '15:00:00', 'end' => '16:00:00'];
$timeslots[] = ['start' => '16:00:00', 'end' => '17:00:00'];
$timeslots[] = ['start' => '17:00:00', 'end' => '18:00:00'];

此阵列的预期结果为:10:3​​0-11:30,14-17

1 个答案:

答案 0 :(得分:0)

您可以创建一个数组,其中开始时间是键,值是带有结束时间和开始时间的数组,但是如果我们发现数组中的开始时间是另一个元素的结束时间,我们更新现有元素。

然后输出分组,使用implode()和从array_map()返回的数组来获取开始时间和最后开始时间的数组,除非这些值相同,在这种情况下只需获取开始时间。

$outputs = array();
foreach($timeslots as $timeslot) {
    $startToCombine = null;
    //see if the current start time exists as an end time for another element
    foreach($outputs as $start=>$output) {
        if ($output['end'] == $timeslot['start']) {
            $startToCombine = $start;
            break;
        }
    }
    if ($startToCombine) {//if we have this end time, combine it
        $outputs[$startToCombine]['end'] = $timeslot['end'];
        $outputs[$startToCombine]['lastStart'] = $timeslot['start'];
    }
    else { //otherwise add the new timeslot
        $outputs[$timeslot['start']] = array(
            'lastStart' => $timeslot['start'],
            'end' => $timeslot['end']
        );
    }
}
implode(', ', array_map(function($start) use ($outputs) {
    if ($outputs[$start]['lastStart'] != $start) {
        return $start.'-'.$outputs[$start]['lastStart'];
    }
    return $start;
},array_keys($outputs)));

Teh Playground上查看此操作。

更新

posted this implementation on code review虽然没有人(其他人)(目前)回答,但有一条评论让我修改了我的技巧。 在my answer中,我将关联数组格式更改为关闭结束时间而不是开始时间。另请注意 foreach 已替换为array_reduce()以遍历时间段。

function combine($timeslots) {
    $outputs = array_reduce($timeslots, function($outputs, $timeslot) {
        if (array_key_exists($timeslot['start'], $outputs)) {
            $timeslotToCombine = $outputs[$timeslot['start']];
            $timeslotToCombine['lastStart'] = $timeslot['start'];
            $outputs[$timeslot['end']] = $timeslotToCombine;
            unset($outputs[$timeslot['start']]);
        }
        else {
            $outputs[$timeslot['end']] = array(
                'start' => $timeslot['start']
                );
        }
        return $outputs;
    }, array());
    return implode(', ', array_map(function($timeslot) {
        if (array_key_exists('lastStart', $timeslot)) {
            return $timeslot['start'].'-'.$timeslot['lastStart'];
        }
        return $timeslot['start'];
    },$outputs));
}

为了证明这一点,请结帐this playground example。当我在http://ideone.comhttp://eval.in上运行两个代码块时,都花费了大约0.01-0.02秒。后者应该更快,因为删除了嵌套循环 - 即复杂性是 O(n)而不是 O(n 2