使用日期数组(业务开放时间)。我想将它们浓缩成最简洁的形式。
到目前为止,我开始使用这种结构
Array
(
[Mon] => 12noon-2:45pm, 5:30pm-10:30pm
[Tue] => 12noon-2:45pm, 5:30pm-10:30pm
[Wed] => 12noon-2:45pm, 5:30pm-10:30pm
[Thu] => 12noon-2:45pm, 5:30pm-10:30pm
[Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
我想要实现的目标是:
Array
(
[Mon-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
我已经尝试过写一个递归函数,并设法输出到目前为止:
Array
(
[Mon-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Tue-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Wed-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Thu-Fri] => 12noon-2:45pm, 5:30pm-10:30pm
[Sat] => 12noon-11pm
[Sun] => 12noon-9:30pm
)
有人能看到一种简单的方法来比较这些值并将它们组合在一起吗?我的递归函数基本上是两个嵌套的foreach()
循环 - 不是很优雅。
谢谢, 马特
编辑:这是我到目前为止的代码,它产生上面的第3个数组(从第一个数组作为输入):$last_time = array('t' => '', 'd' => ''); // blank array for looping
$i = 0;
foreach($final_times as $day=>$time) {
if($last_time['t'] != $time ) { // it's a new time
if($i != 0) { $print_times[] = $day . ' ' . $time; }
// only print if it's not the first, otherwise we get two mondays
} else { // this day has the same time as last time
$end_day = $day;
foreach($final_times as $day2=>$time2) {
if($time == $time2) {
$end_day = $day2;
}
}
$print_times[] = $last_time['d'] . '-' . $end_day . ' ' . $time;
}
$last_time = array('t' => $time, 'd' => $day);
$i++;
}
答案 0 :(得分:1)
我认为没有一个特别优雅的解决方案。经过多次试验内置的array_*
函数试图找到一个很好的简单解决方案后,我放弃了并想出了这个:
$lastStart = $last = $lastDay = null;
$new = array();
foreach ($arr as $day => $times) {
if ($times != $last) {
if ($last != null) {
$key = $lastStart == $lastDay ? $lastDay : $lastStart . '-' . $lastDay;
$new[$key] = $last;
}
$lastStart = $day;
$last = $times;
}
$lastDay = $day;
}
$key = $lastStart == $lastDay ? $lastDay : $lastStart . '-' . $lastDay;
$new[$key] = $last;
它只使用一个foreach循环而不是你的两个,因为它保持一堆状态。它只会将相邻的日子合并在一起(例如,如果星期三改变,你就不会得到像Mon-Tue,Thu-Fri
这样的东西,你会得到两个单独的条目。)
答案 1 :(得分:1)
我通过将其建模为关系数据库来接近它:
day start end
1 12:00 14:45
1 17:30 22:30
...
然后它很容易减少 - 有特定的时间间隔:
SELECT DISTINCT start,end 从时间表开始;
这些将在特定日期发生:
SELECT start,end,GROUP_CONCAT(day)ORDER BY day SEPERATOR',' 从时间表 GROUP BY开始,结束
(这使用仅限MySQL的'group_concat'函数 - 但该方法在无法使用的情况下相同) 会给:
12:00 14:45 1,2,3,4,5
17:30 22:30 1,2,3,4,5
12:00 23:00 6
12:00 21:30 7
然后从日期列表中计算出连续的日期范围相当简单。
下进行。
答案 2 :(得分:1)
作为替代方案,我设法使用array_*
函数拼凑了一个版本。但在某些时候,“优雅”,“效率”和“可读性”都被打包并离开了。然而,它确实处理了我在另一个答案中提到的边缘情况,它给我留下了一个温暖的光芒,证明它可以以一种功能性的方式完成(但同时又感到羞耻......)< / p>
$days = array_keys($arr);
$dayIndices = array_flip($days);
var_dump(array_flip(array_map(
function ($mydays) use($days, $dayIndices) {
return array_reduce($mydays,
function($l, $r) use($days, $dayIndices) {
if ($l == '') { return $r; }
if (substr($l, -3) == $days[$dayIndices[$r] - 1]) {
return ((strlen($l) > 3 && substr($l, -4, 1) == '-') ? substr($l, 0, -3) : $l) . '-' . $r;
}
return $l . ',' . $r;
}, '');
}, array_map(
function ($day) use ($arr) {
return array_keys($arr, $arr[$day]);
}, array_flip($arr)
)
)));
我用这个输入测试了它:
'Mon' => '12noon-2:45pm, 5:30pm-10:30pm', 'Tue' => '12noon-2:45pm, 5:30pm-10:30pm', 'Wed' => '12noon-2:45pm, 5:30pm-10:00pm', 'Thu' => '12noon-2:45pm, 5:30pm-10:30pm', 'Fri' => '12noon-2:45pm, 5:30pm-10:00pm', 'Sat' => '12noon-2:45pm, 5:30pm-10:30pm', 'Sun' => '12noon-9:30pm'
得到了这个:
["Mon-Tue,Thu,Sat"]=> string(29) "12noon-2:45pm, 5:30pm-10:30pm" ["Wed,Fri"]=> string(29) "12noon-2:45pm, 5:30pm-10:00pm" ["Sun"]=> string(13) "12noon-9:30pm"
基本上,最后的array_map
会将输入转换为关联数组,这些数组会出现在它们出现的天数数组中。之前的大块代码使用array_reduce
将这些天数缩减为格式良好的字符串,咨询$days
和$dayIndices
数组以检查天数是否连续。