时代设定联盟和消除

时间:2017-10-28 23:22:01

标签: php algorithm

我有一个包含开始和结束时间的事件列表,如下所示:

diagflow.handleIncoming

在上面的列表中,开始按顺序递增。我需要以下内容:

  1. 应删除第2项和第3项,因为它完全是第1项的子集
  2. 第1项和第4项以及第5项和第6项应合并为两项,分别为1开始,11日结束,12日结束,25日结束。
  3. 所以最后我应该只有两个项而不是6.我无法弄清楚任何处理这个问题的算法。

    我尝试使用以下内容循环浏览列表的项目:

    Id     Start      End
    1      1           10
    2      4           9
    3      5           8
    4      6           11
    5      12          20
    6      18          25
    

    我的主要问题是:是否有任何已知的算法可以解决这个问题? , PHP实现是首选,但也欢迎任何其他实现。

1 个答案:

答案 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)
  }
}