按照最近的开始日期和结束日期对对象进行分组的最佳逻辑是什么?


What's the best logic for grouping objects by closest start and end dates?

我有一个项目数组,它们都有关联的开始和结束日期。我想根据最接近的开始和结束日期对它们进行分组,而不让它们重叠,但是我很难想象这样做的逻辑应该是什么样子的。

假设我从这个开始:

$query = array(
[0] =>
   array(
   [0] =>
        array(
        ['name'] =>'A'
        ['start'] =>'1/1/2011'
        ['end'] =>'1/31/2011'
        )
   [1] =>
        array(
        ['name'] =>'B'
        ['start'] =>'1/15/2011'
        ['end'] =>'1/31/2011'
        )
   [2] =>
        array(
        ['name'] =>'C'
        ['start'] =>'2/1/2011'
        ['end'] =>'2/28/2011'
        )
   [3] =>
        array(
        ['name'] =>'D'
        ['start'] =>'2/2/2011'
        ['end'] =>'2/28/2011'
        )
   [4] =>
        array(
        ['name'] =>'E'
        ['start'] =>'1/31/2011'
        ['end'] =>'3/1/2011'
        )
   [5] =>
        array(
        ['name'] =>'F'
        ['start'] =>'3/3/2011'
        ['end'] =>'3/31/2011'
        )
    )
)

我想以这个结尾:

$result = array(
[0] =>
   array(
   [0] =>
        array(
        ['name'] =>'A'
        ['start'] =>'1/1/2011'
        ['end'] =>'1/31/2011'
        )
   [1] =>
        array(
        ['name'] =>'C'
        ['start'] =>'2/1/2011'
        ['end'] =>'2/28/2011'
        )
   [2] =>
        array(
        ['name'] =>'F'
        ['start'] =>'3/3/2011'
        ['end'] =>'3/31/2011'
        )
   )
[1]=> 
   array(
   [0] =>
        array(
        ['name'] =>'B'
        ['start'] =>'1/15/2011'
        ['end'] =>'1/31/2011'
        )
   [1] =>
        array(
        ['name'] =>'D'
        ['start'] =>'2/2/2011'
        ['end'] =>'2/28/2011'
        )
   )
[2]=>
   array(
   [0] =>
        array(
        ['name'] =>'E'
        ['start'] =>'1/31/2011'
        ['end'] =>'3/1/2011'
        )
    )
)

根据请求编辑,上面列出的输入和输出的var_export:

$query = array ( 0 => array ( 'name' => 'A', 'start' => '1/1/2011', 'end' => '1/31/2011', ), 1 => array ( 'name' => 'B', 'start' => '1/15/2011', 'end' => '1/31/2011', ), 2 => array ( 'name' => 'C', 'start' => '2/1/2011', 'end' => '2/28/2011', ), 3 => array ( 'name' => 'D', 'start' => '2/2/2011', 'end' => '2/28/2011', ), 4 => array ( 'name' => 'E', 'start' => '1/31/2011', 'end' => '3/1/2011', ), 5 => array ( 'name' => 'F', 'start' => '3/3/2011', 'end' => '3/31/2011', ), ) 
$result = array ( 0 => array ( 0 => array ( 'name' => 'A', 'start' => '1/1/2011', 'end' => '1/31/2011', ), 1 => array ( 'name' => 'C', 'start' => '2/1/2011', 'end' => '2/28/2011', ), 2 => array ( 'name' => 'F', 'start' => '3/3/2011', 'end' => '3/31/2011', ), ), 1 => array ( 0 => array ( 'name' => 'B', 'start' => '1/15/2011', 'end' => '1/31/2011', ), 1 => array ( 'name' => 'D', 'start' => '2/2/2011', 'end' => '2/28/2011', ), ), 2 => array ( 0 => array ( 'name' => 'E', 'start' => '1/31/2011', 'end' => '3/1/2011', ), ), )
到目前为止,我最好的方法是循环遍历$query中的项,并将每个数组中最后一个项的开始日期与结束日期进行比较。即使在我输入这个的时候,我也意识到这将假设我们从一个已经按时间顺序排列的$query数组开始(它是随机的)

我们正在尝试将GANTT时间线与这些数据放在一起,使用尽可能少的行来帮助可视化我们的开放时间表。这把我难住了。谁能指出最有效的组织这些对象的方法,我将不胜感激。

我相信这是答案的开始。

我循环通过$查询和使用unset()对每个对象,因为它被添加到$result内的数组。

希望这里写的内容尽可能高效:

function cmp($a, $b){ 
return strcmp($a['start'], $b['start']); 
}
$query = array(array('name' =>'A','start' =>'1/1/2011','end' =>'1/31/2011'),array('name' =>'B','start' =>'1/15/2011','end' =>'1/31/2011'),array('name' =>'C','start' =>'2/1/2011','end' =>'2/28/2011'),array('name' =>'D','start' =>'2/2/2011','end' =>'2/28/2011'),array('name' =>'E','start' =>'1/31/2011','end' =>'3/1/2011'), array('name' =>'F','start' =>'3/3/2011','end' =>'3/31/2011'));
usort($query, "cmp"); // organize by start date
$result = array(); 
$c = count($query);
for($i = 1; $i <= $c; $i++) {
if (empty($result)) {
    $result[0][0] = $query[0];
    unset($query[0]);
    $query = array_values($query);  
} else {
    $lastkey_group = array_pop(array_keys($result)); 
    $lastkey_object = array_pop(array_keys($result[$lastkey_group]));
    // get the last object's end date
    $last_end_date = strtotime($result[$lastkey_group][$lastkey_object]['end']);
    $match_days = 1000;
    $match_key = 1000;
    foreach($query as $key => $q) {
        $this_start_date = strtotime($q['start']);
        $diff = round(($this_start_date - $last_end_date)/86400);
        // compare to start date in each $q
        if($diff < $match_days && $diff >= 0) {                     
            // if the distance is greater than 0 but less than $diff, 
            // replace match with distance and row key
            $match_days = $diff;
            $match_key = $key;
        } 
    }

    if($match_key == 1000) {                
        $result[$lastkey_group + 1][0] = $query[0]; // no good matches. write to a new group 
        unset($query[0]);       
        $query = array_values($query);
    } else {
        $result[$lastkey_group][$lastkey_object + 1] = $query[$match_key]; 
            // match. write to this group
        unset($query[$match_key]);
        $query = array_values($query);
    }   
}
}
 var_dump($result);

下面是它的输出:

array(3) { [0]=> array(3) { [0]=> array(3) { ["name"]=> string(1) "A" ["start"]=> string(8) "1/1/2011" ["end"]=> string(9) "1/31/2011" } [1]=> array(3) { ["name"]=> string(1) "E" ["start"]=> string(9) "1/31/2011" ["end"]=> string(8) "3/1/2011" } [2]=> array(3) { ["name"]=> string(1) "F" ["start"]=> string(8) "3/3/2011" ["end"]=> string(9) "3/31/2011" } } [1]=> array(2) { [0]=> array(3) { ["name"]=> string(1) "B" ["start"]=> string(9) "1/15/2011" ["end"]=> string(9) "1/31/2011" } [1]=> array(3) { ["name"]=> string(1) "C" ["start"]=> string(8) "2/1/2011" ["end"]=> string(9) "2/28/2011" } } [2]=> array(1) { [0]=> array(3) { ["name"]=> string(1) "D" ["start"]=> string(8) "2/2/2011" ["end"]=> string(9) "2/28/2011" } } }