我有一个包含开始和结束时间的事件列表,如下所示:
diagflow.handleIncoming
在上面的列表中,开始按顺序递增。我需要以下内容:
所以最后我应该只有两个项而不是6.我无法弄清楚任何处理这个问题的算法。
我尝试使用以下内容循环浏览列表的项目:
Id Start End
1 1 10
2 4 9
3 5 8
4 6 11
5 12 20
6 18 25
我的主要问题是:是否有任何已知的算法可以解决这个问题? , PHP实现是首选,但也欢迎任何其他实现。
答案 0 :(得分:2)
我认为应该有一个比自定义算法更好的算法,因为当需求发生变化时,更容易调整它。
以下是任何开发人员都应该理解的工作版本:
<?php
$input = [
['id' => 1, 'start' => 1, 'end' => 10 ],
['id' => 2, 'start' => 4, 'end' => 9 ],
['id' => 3, 'start' => 5, 'end' => 8 ],
['id' => 4, 'start' => 6, 'end' => 11 ],
['id' => 5, 'start' => 12, 'end' => 20 ],
['id' => 6, 'start' => 18, 'end' => 25 ],
];
$output = [];
$output[] = $input[0];
foreach ($input as $event) {
if (isEventEqual($event, $output) or isEventFullyInside($event, $output)) {
continue;
} elseif (isEventFullyOutside($event, $output)) {
$output[] = $event;
} elseif (isEventFullyWrap($event, $output)) {
$output[isEventFullyWrap($event, $output)] = $event;
} elseif (wasEventStartedBeforeAndFinishedInside($event, $output)) {
list($indexOfEventToUpdate, $updatedEvent) = wasEventStartedBeforeAndFinishedInside($event, $output);
$output[$indexOfEventToUpdate] = $updatedEvent;
} elseif (wasEventStartedInsideAndFinishedAfter($event, $output)) {
list($indexOfEventToUpdate, $updatedEvent) = wasEventStartedInsideAndFinishedAfter($event, $output);
$output[$indexOfEventToUpdate] = $updatedEvent;
}
}
var_dump($output);
function isEventEqual($event, $output) {
$isEventEqual = false;
foreach($output as $checked) {
if ($checked['start'] === $event['start'] and $checked['end'] === $event['end']) {
$isEventEqual = true;
}
}
return $isEventEqual;
}
function isEventFullyOutside($event, $output) {
$isEventFullyOutside = false;
foreach($output as $checked) {
$isEventFullyBefore = $event['end'] < $checked['start'];
$isEventFullyAfter = $event['start'] > $checked['end'];
$isEventFullyOutside = ($isEventFullyBefore or $isEventFullyAfter);
}
return $isEventFullyOutside;
}
function isEventFullyInside($event, $output) {
$isEventFullyInside = false;
foreach($output as $checked) {
$isEventStartedAfter = $event['start'] > $checked['start'];
$isEventFinishedBefore = $event['end'] < $checked['end'];
$isEventFullyInside = ($isEventStartedAfter and $isEventFinishedBefore);
}
return $isEventFullyInside;
}
function isEventFullyWrap($event, $output) {
foreach($output as $index => $checked) {
if ($checked['start'] > $event['start'] and $checked['end'] < $event['end']) {
return $index;
}
}
return false;
}
function wasEventStartedBeforeAndFinishedInside($event, $output) {
foreach($output as $index => $checked) {
if ($checked['start'] > $event['start'] and $checked['start'] > $event['end'] and $checked['end'] > $event['end']) {
$checked['start'] = $event['start'];
return [$index, $checked];
}
}
return false;
}
function wasEventStartedInsideAndFinishedAfter($event, $output) {
foreach($output as $index => $checked) {
if ($checked['start'] < $event['start'] and $checked['end'] > $event['start'] and $checked['end'] < $event['end']) {
$checked['end'] = $event['end'];
return [$index, $checked];
}
}
return false;
}
我不喜欢命名和混淆,一些函数返回布尔值,一个返回整数,另外两个返回数组,但作为算法草案来说明这个想法,我认为它是可以接受的。
输出:
array(2) {
[0] =>
array(3) {
'id' => int(1)
'start' => int(1)
'end' => int(11)
}
[1] =>
array(3) {
'id' => int(5)
'start' => int(12)
'end' => int(25)
}
}