RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 604025
Accepted
ForgottenPark
ForgottenPark
Asked:2020-12-15 23:44:36 +0000 UTC2020-12-15 23:44:36 +0000 UTC 2020-12-15 23:44:36 +0000 UTC

删除日期范围数组中的冲突

  • 772

有一个不考虑时间的日期周期数组(为清楚起见,我将日期设置为字符串,但实际上是时间戳):

$items = [
['fromDate' => '2016-01-01', 'toDate' => '2016-01-12'],
['fromDate' => '2016-02-02', 'toDate' => '2016-02-12'],
['fromDate' => '2016-03-01', 'toDate' => '2016-03-01'],
['fromDate' => '2016-01-05', 'toDate' => '2016-01-16'],
// ...
];

问题:如何将 $items 转换为合并日期冲突?例如,有一个句点01.01.2016 — 10.01.2016and 05.01.2016 — 12.01.2016,那么我们应该得到一个而不是两个元素 - 01.01.2016 — 12.01.2016。

另一个例子:01.03.2017 — 04.03.2017和05.03.2017 — 05.03.2017在01.03.2017 — 05.03.2017.

合并后,新范围也可以与其他元素合并。在输出中,我们应该得到相同的 $items 数组,只有合并的碰撞(如果有的话)。

php
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Anton Shchyrov
    2020-12-16T00:23:10Z2020-12-16T00:23:10Z

    像这样的东西

    function cmp($a, $b) {
      if ($a["from"] == $b["from"]) {
        if ($a["to"] == $b["to"]) {
          return 0;
          return ($a["to"] < $b["to"]) ? -1 : 1;
        }
        return ($a["from"] < $b["from"]) ? -1 : 1;
      }
    }
    
    if (count($items) == 0)
      return null;
    usort($items, "cmp");
    $res = array();
    $curItem = $items[0];
    foreach ($items as $item) {
      if ($curItem['to'] + 3600 * 24 /*1 day*/ >= $item['from'])
        $curItem['to'] = $item['to'];
      else {
        $res[] = $curItem;
        $curItem = $item;
      }
    }
    $res[] = $curItem;
    return $res;
    
    1. 对原始数组进行排序
    2. 获取数组的第一个元素
    3. 如果下一个元素可以粘合到当前元素,我们粘合
    4. 否则 - 将当前元素添加到结果数组并获取下一个元素
    • 1
  2. Redr01d
    2020-12-16T02:45:59Z2020-12-16T02:45:59Z

    如果你根本不计算,只是按月排序,选择 min-max,那么像这样:

    $struct = [];
    $items = [
        ['fromDate' => '2016-01-01', 'toDate' => '2016-01-12'],
        ['fromDate' => '2016-02-02', 'toDate' => '2016-02-12'],
        ['fromDate' => '2016-03-01', 'toDate' => '2016-03-01'],
        ['fromDate' => '2016-01-05', 'toDate' => '2016-01-16']
    ];
    //объединим все даты в 1 массив
    $dates = array_merge(array_column($items , 'fromDate') , array_column($items, 'toDate'));
    
    //разложим все даты по месяцам
    array_map(function($date)use(&$struct){
            $m = new DateTime($date);
            $struct[$m->format('m')][] = $date;
    }, $dates);
    
    //выбираем min max дату в месяце
    $items = array_map(function($range){
            return [
                'fromDate' => min($range),'toDate' => max($range)
            ];
    }, $struct);
    
    print_r($items);
    

    在出口处

       [01] => Array
            (
                [fromDate] => 2016-01-01
                [toDate] => 2016-01-16
            )
    
        [02] => Array
            (
                [fromDate] => 2016-02-02
                [toDate] => 2016-02-12
            )
    
        [03] => Array
            (
                [fromDate] => 2016-03-01
                [toDate] => 2016-03-01
            )
    

    关于对话中阐明的条件,我正在更新帖子,现在无论月份如何,它都会被吸收,整个日期范围都被考虑在内。

    $items = [
        ['fromDate' => '2016-01-01', 'toDate' => '2016-01-12'],
        ['fromDate' => '2016-02-02', 'toDate' => '2016-02-12'],
        ['fromDate' => '2016-02-12', 'toDate' => '2016-02-22'],
        ['fromDate' => '2016-03-01', 'toDate' => '2016-03-01'],
        ['fromDate' => '2016-01-03', 'toDate' => '2016-01-10'],
        ['fromDate' => '2016-01-05', 'toDate' => '2016-01-16'],
        ['fromDate' => '2013-10-10', 'toDate' => '2013-12-13'],
        ['fromDate' => '2012-01-01', 'toDate' => '2015-03-10'],
    ];
    
    $startDates = array_column($items , 'fromDate');
    array_walk($items, function(&$item)use($startDates , &$items){
    
        //диапазон всех дат входящих в период 
        $end = new DateTime($item['toDate']);
        $period = new DatePeriod(
             new DateTime($item['fromDate']),
             new DateInterval('P1D'),
             $end->modify("+1 day"),
             DatePeriod::EXCLUDE_START_DATE
        );
        //итератор периода
        foreach ($period as $date) {
            $search = $date->format('Y-m-d');
            //ищем наличие пересечения, если оно есть удаляем диапазон из массива , 
            //если в удаляемом массиве конечная дата выше , обновляем ее
            $id = array_search($search , $startDates);
            if($id !== false){
                if($item['toDate'] < $items[$id]['toDate']){
                    $item['toDate'] = $items[$id]['toDate'];
                }
                unset($items[$id]);
    
            }
        }   
    });
    
    print_r($items);
    
    • 1
  3. Best Answer
    ForgottenPark
    2020-12-19T16:49:49Z2020-12-19T16:49:49Z

    谢谢大家,谢谢你们,结果是我自己:

        function mergeChunks($items)
        {
            $sorter = function ($a, $b) {
                if ($a['from'] == $b['from']) {
                    return 0;
                }
    
                return $a['from'] < $b['from'] ? -1 : 1;
            };
    
            usort($items, $sorter);
    
            $sortBox = [];
    
            for ($i = 0; $i < count($items) - 1; $i++) {
                $item1 = $items[$i];
                $item2 = $items[$i + 1];
    
                if (strtotime($item1['to']) >= strtotime($item2['from']) - 86400) {
                    $item1['to'] = $item1['to'] >= $item2['to'] ? $item1['to'] : $item2['to'];
                    $sortBox[] = $item1;
                    $sortBox = array_merge($sortBox, array_slice($items, $i + 2));
    
                    return mergeChunks($sortBox);
                } else {
                    $sortBox[] = $item1;
    
                    if ($i == count($items) - 2) {
                        $sortBox[] = $item2;
                    }
                }
            }
    
            usort($sortBox, $sorter);
    
            return $sortBox;
        }
    
        $items = mergeChunks([
            ['from' => '2016-01-01', 'to' => '2016-01-05'],
            ['from' => '2016-01-06', 'to' => '2016-03-15'],
            ['from' => '2016-02-01', 'to' => '2016-02-15'],
            ['from' => '2016-07-02', 'to' => '2016-08-15'],
        ]);
    
        print_r($items);
    
        // Результат:
        // ['from' => '2016-01-01', 'to' => '2016-03-15'],
        // ['from' => '2016-07-02', 'to' => '2016-08-15'],
    
    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5