【问题标题】:What's the best logic for grouping objects by closest start and end dates?按最接近的开始和结束日期对对象进行分组的最佳逻辑是什么?
【发布时间】:2011-12-13 16:19:14
【问题描述】:

我有一组项目,它们都有与之相关的开始和结束日期。我想根据最接近的开始日期和结束日期对它们进行分组,而不会有任何重叠,但我很难想象这应该是什么样的逻辑。

假设我从这个开始:

$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 时间线与这些数据放在一起,使用尽可能少的行来帮助可视化我们的开放时间表的样子。它让我难过。谁能指出组织这些对象的最有效方法,将不胜感激。

【问题讨论】:

  • “最近的开始日期和结束日期”这个词并不准确......您展示了很好的输入和输出,但如果您希望我们提供任何建议,我们仍然需要了解这一点......
  • 考虑添加 var_export() 输出以方便人们尝试提供帮助。
  • @MathieuDumoulin - 另一种表述任务的方式 - 我想将对象排列成尽可能少的组,开始和结束之间的间隙尽可能少。如果对象 C 的开始日期从对象 A 中删除了 3 天,但从对象 B 中仅删除了 1 天,我希望它与对象 B 一起进入组。
  • @chris 感谢您的建议。我编辑了原始问题以包含它。

标签: php database json


【解决方案1】:

我认为这是答案的开始。

我在 $query 中循环并在每个对象上使用 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" } } } 

【讨论】:

    猜你喜欢
    • 2016-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-04
    • 2021-07-21
    相关资源
    最近更新 更多