php 根据呼叫开始和结束时间计算最大重叠呼叫

qaxu7uf2  于 2023-09-29  发布在  PHP
关注(0)|答案(2)|浏览(118)

我有一个输入文件,其中调用开始日期时间和调用结束日期时间由'分隔|'。我正在尝试逐行读取文件并计算重叠/并发调用的最大数量。我一直在努力,但我似乎不能得到正确的。
输入文件示例:

2023-01-19 11:18:17|2023-01-19 11:21:59
2023-01-19 11:18:30|2023-01-19 11:19:06
2023-01-19 11:18:58|2023-01-19 11:20:04
2023-01-19 11:20:56|2023-01-19 11:21:56
2023-01-19 11:21:18|2023-01-19 11:24:42
2023-01-19 11:21:26|2023-01-19 11:22:02
2023-01-19 11:21:56|2023-01-19 11:22:38
2023-01-19 11:22:47|2023-01-19 11:26:59
2023-01-19 11:23:40|2023-01-19 11:24:58
2023-01-19 11:25:10|2023-01-19 11:25:46
2023-01-19 11:25:51|2023-01-19 11:27:57
2023-01-19 11:26:01|2023-01-19 11:26:37
2023-01-19 11:26:01|2023-01-19 11:27:37
2023-01-19 11:26:19|2023-01-19 11:26:55
2023-01-19 11:27:23|2023-01-19 11:28:59
2023-01-19 11:27:35|2023-01-19 11:27:47
2023-01-19 11:28:26|2023-01-19 11:28:38

我的代码目前看起来像这样(我道歉,我在这里的文本编辑器中遇到了困难,所以它看起来有点脱节,并且在函数名称后缺少一个“{”...):

function readcsv($filename) {

  $handle = fopen($filename, "r");
  if ($handle) {

    $data = [];
    $max = 0;
    $calls = 0;
    $datetime = "";
    while (($line = fgetcsv($handle, null, "|")) !== false) {

        if (!isset($data["previousendmax"])) {
            $data["previousendmax"] = $line[1];
        }

        if (!isset($data["previousendmin"])) {
            $data["previousendmin"] = $line[0];
        }

        $startdate = $line[0];
        $enddate = $line[1];

        if (
            $startdate >= $data["previousendmin"] &&
            $startdate <= $data["previousendmax"]
        ) {
            $calls++;
        }
        if (
            $enddate > $data["previousendmax"] ||
            $startdate > $data["previousendmax"]
        ) {
            $calls--;
        }

        if ($startdate > $data["previousendmin"]) {
            $data["previousendmin"] = $enddate;
        }
        if ($enddate > $data["previousendmax"]) {
            $data["previousendmax"] = $enddate;
        }

        if ($calls > $max) {
            $max = $calls;
            $data["previousend"] = $line[1];
            $datetime = $line[0];
        }
        echo "Current Calls: " . $calls . "\n";
        echo "Max Calls: " . $max . "\n";
        print_r($data["previousendmin"]);
        echo "\n";
        print_r($data["previousendmax"]);
        echo "\n";
    }
    fclose($handle);
}

print_r($max);

当前输出为:

Current Calls: 1
Max Calls: 1
2023-01-19 11:18:17
2023-01-19 11:21:59
Current Calls: 2
Max Calls: 2
2023-01-19 11:19:06
2023-01-19 11:21:59
Current Calls: 2
Max Calls: 2
2023-01-19 11:19:06
2023-01-19 11:21:59
Current Calls: 3
Max Calls: 3
2023-01-19 11:21:56
2023-01-19 11:21:59
Current Calls: 2
Max Calls: 3
2023-01-19 11:21:56
2023-01-19 11:24:42
Current Calls: 2
Max Calls: 3
2023-01-19 11:21:56
2023-01-19 11:24:42
Current Calls: 3
Max Calls: 3
2023-01-19 11:21:56
2023-01-19 11:24:42
Current Calls: 3
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:26:59
Current Calls: 3
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:26:59
Current Calls: 3
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:26:59
Current Calls: 2
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:27:57
Current Calls: 2
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:27:57
Current Calls: 2
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:27:57
Current Calls: 2
Max Calls: 3
2023-01-19 11:26:59
2023-01-19 11:27:57
Current Calls: 2
Max Calls: 3
2023-01-19 11:28:59
2023-01-19 11:28:59
Current Calls: 2
Max Calls: 3
2023-01-19 11:28:59
2023-01-19 11:28:59
Current Calls: 2
Max Calls: 3
2023-01-19 11:28:59
2023-01-19 11:28:59
3

当然,在列表的末尾,它应该显示零调用,这样我就知道它没有按预期工作。如果我手动查看前6行列表,我希望并发呼叫如下:

1
2
3
2
3
4

我纠结的地方是如何解释在下一行开始之前结束的呼叫...但恰好在我正在评估的那一行上面几行。例如,第4行从11:20:56开始,这意味着当调用开始时,第2行和第3行上的调用都已结束。有人能给我指个正确的方向吗?谢谢你,谢谢
我尝试构建一个滚动的时间“窗口”,然后计算在该窗口内同时进行的调用数量,但这种方法并不像预期的那样工作(当然是因为我是新手,做错了)。

bvjveswy

bvjveswy1#

我和一位同事谈过,他提出了以下建议:当一个调用开始时,它是+1当一个调用结束时,它是-1所以把行分开。以前6行为例:

2023-01-19 11:18:17,+1
2023-01-19 11:18:30,+1
2023-01-19 11:18:58,+1
2023-01-19 11:20:56,+1
2023-01-19 11:21:18,+1
2023-01-19 11:21:26,+1
2023-01-19 11:21:59,-1
2023-01-19 11:19:06,-1
2023-01-19 11:20:04,-1
2023-01-19 11:21:56,-1
2023-01-19 11:24:42,-1
2023-01-19 11:22:02,-1

然后,按日期/时间排序并计算它们:

2023-01-19 11:18:17,+1 - 1
2023-01-19 11:18:30,+1 - 2
2023-01-19 11:18:58,+1 - 3
2023-01-19 11:19:06,-1 - 2
2023-01-19 11:20:04,-1 - 1
2023-01-19 11:20:56,+1 - 2
2023-01-19 11:21:18,+1 - 3
2023-01-19 11:21:26,+1 - 4
2023-01-19 11:21:56,-1 - 3
2023-01-19 11:21:59,-1 - 2
2023-01-19 11:22:02,-1 - 1
2023-01-19 11:24:42,-1 - 0

当你这样接近它的时候,很容易!

0tdrvxhp

0tdrvxhp2#

如果我从OP的输出中正确理解了这个问题,那么问题是找到更改之间的时间段,其中更改是电话呼叫开始或电话呼叫结束。
为了更简单的测试,让我们从数组开始,而不是阅读CSV文件(这与问题无关):

$input = [
    [ '2023-01-19 11:18:17', '2023-01-19 11:21:59' ],
    [ '2023-01-19 11:18:30', '2023-01-19 11:19:06' ],
    [ '2023-01-19 11:18:58', '2023-01-19 11:20:04' ],
    [ '2023-01-19 11:20:56', '2023-01-19 11:21:56' ],
    [ '2023-01-19 11:21:18', '2023-01-19 11:24:42' ],
    [ '2023-01-19 11:21:26', '2023-01-19 11:22:02' ],
    [ '2023-01-19 11:21:56', '2023-01-19 11:22:38' ],
    [ '2023-01-19 11:22:47', '2023-01-19 11:26:59' ],
    [ '2023-01-19 11:23:40', '2023-01-19 11:24:58' ],
    [ '2023-01-19 11:25:10', '2023-01-19 11:25:46' ],
    [ '2023-01-19 11:25:51', '2023-01-19 11:27:57' ],
    [ '2023-01-19 11:26:01', '2023-01-19 11:26:37' ],
    [ '2023-01-19 11:26:01', '2023-01-19 11:27:37' ],
    [ '2023-01-19 11:26:19', '2023-01-19 11:26:55' ],
    [ '2023-01-19 11:27:23', '2023-01-19 11:28:59' ],
    [ '2023-01-19 11:27:35', '2023-01-19 11:27:47' ],
    [ '2023-01-19 11:28:26', '2023-01-19 11:28:38' ],
];

$date_times = [];

foreach ($input as $item) {
    $date_times[] = [
        'start' => true,
        'time'  => DateTime::createFromFormat('Y-m-d H:i:s', $item[0]),
        'item'  => $item
    ];
    $date_times[] = [
        'start' => false,
        'time'  => DateTime::createFromFormat('Y-m-d H:i:s', $item[1]),
        'item'  => $item
    ];
}

usort($date_times, fn($item1, $item2) => $item1['time'] <=> $item2['time']);

$result = [];

$temp_items = [];
$max = 0;

for ($i = 1; $i < count($date_times); $i++) {
    if ($date_times[$i - 1]['start']) {
        $temp_items[] = $date_times[$i - 1]['item'];
    } else {
        $index = array_search($date_times[$i - 1]['item'], $temp_items, true);
        unset($temp_items[$index]);
    }
    $result[] = [
        'from'  => $date_times[$i - 1]['time'],
        'till'  => $date_times[$i]['time'],
        'count' => $count = count($temp_items),
        'max'   => $max = max($max, $count),
        'item'  => $date_times[$i - 1]['item'],
        'items' => $temp_items,
    ];
}

echo "Period      Calls  Max  Items\n";
echo "----------------------------------------------------------------------------------------\n";
foreach ($result as $item) {
    echo $item['from']->format('i:s') . '-' . $item['till']->format('i:s') . '   ';
    echo $item['count'] . '     ';
    echo $item['max'] . '   ';
    foreach ($item['items'] as $index => $sub_items) {
        echo rtrim(str_replace('2023-01-19 11:', '', $sub_items[0] . '-' . $sub_items[1]) . ', ', ', ');
    }
    echo "\n";
}

输出量:

Period      Calls  Max  Items
----------------------------------------------------------------------------------------
18:17-18:30   1     1   18:17-21:59
18:30-18:58   2     2   18:17-21:59, 18:30-19:06
18:58-19:06   3     3   18:17-21:59, 18:30-19:06, 18:58-20:04
19:06-20:04   2     3   18:17-21:59, 18:58-20:04
20:04-20:56   1     3   18:17-21:59
20:56-21:18   2     3   18:17-21:59, 20:56-21:56
21:18-21:26   3     3   18:17-21:59, 20:56-21:56, 21:18-24:42
21:26-21:56   4     4   18:17-21:59, 20:56-21:56, 21:18-24:42, 21:26-22:02
21:56-21:56   3     4   18:17-21:59, 21:18-24:42, 21:26-22:02
21:56-21:59   4     4   18:17-21:59, 21:18-24:42, 21:26-22:02, 21:56-22:38
21:59-22:02   3     4   21:18-24:42, 21:26-22:02, 21:56-22:38
22:02-22:38   2     4   21:18-24:42, 21:56-22:38
22:38-22:47   1     4   21:18-24:42
22:47-23:40   2     4   21:18-24:42, 22:47-26:59
23:40-24:42   3     4   21:18-24:42, 22:47-26:59, 23:40-24:58
24:42-24:58   2     4   22:47-26:59, 23:40-24:58
24:58-25:10   1     4   22:47-26:59
25:10-25:46   2     4   22:47-26:59, 25:10-25:46
25:46-25:51   1     4   22:47-26:59
25:51-26:01   2     4   22:47-26:59, 25:51-27:57
26:01-26:01   3     4   22:47-26:59, 25:51-27:57, 26:01-26:37
26:01-26:19   4     4   22:47-26:59, 25:51-27:57, 26:01-26:37, 26:01-27:37
26:19-26:37   5     5   22:47-26:59, 25:51-27:57, 26:01-26:37, 26:01-27:37, 26:19-26:55
26:37-26:55   4     5   22:47-26:59, 25:51-27:57, 26:01-27:37, 26:19-26:55
26:55-26:59   3     5   22:47-26:59, 25:51-27:57, 26:01-27:37
26:59-27:23   2     5   25:51-27:57, 26:01-27:37
27:23-27:35   3     5   25:51-27:57, 26:01-27:37, 27:23-28:59
27:35-27:37   4     5   25:51-27:57, 26:01-27:37, 27:23-28:59, 27:35-27:47
27:37-27:47   3     5   25:51-27:57, 27:23-28:59, 27:35-27:47
27:47-27:57   2     5   25:51-27:57, 27:23-28:59
27:57-28:26   1     5   27:23-28:59
28:26-28:38   2     5   27:23-28:59, 28:26-28:38
28:38-28:59   1     5   27:23-28:59

如果问题只是关于在同一时间获得最大调用,那么这就可以了:

$input = [
    [ '2023-01-19 11:18:17', '2023-01-19 11:21:59' ],
    [ '2023-01-19 11:18:30', '2023-01-19 11:19:06' ],
    [ '2023-01-19 11:18:58', '2023-01-19 11:20:04' ],
    [ '2023-01-19 11:20:56', '2023-01-19 11:21:56' ],
    [ '2023-01-19 11:21:18', '2023-01-19 11:24:42' ],
    [ '2023-01-19 11:21:26', '2023-01-19 11:22:02' ],
    [ '2023-01-19 11:21:56', '2023-01-19 11:22:38' ],
    [ '2023-01-19 11:22:47', '2023-01-19 11:26:59' ],
    [ '2023-01-19 11:23:40', '2023-01-19 11:24:58' ],
    [ '2023-01-19 11:25:10', '2023-01-19 11:25:46' ],
    [ '2023-01-19 11:25:51', '2023-01-19 11:27:57' ],
    [ '2023-01-19 11:26:01', '2023-01-19 11:26:37' ],
    [ '2023-01-19 11:26:01', '2023-01-19 11:27:37' ],
    [ '2023-01-19 11:26:19', '2023-01-19 11:26:55' ],
    [ '2023-01-19 11:27:23', '2023-01-19 11:28:59' ],
    [ '2023-01-19 11:27:35', '2023-01-19 11:27:47' ],
    [ '2023-01-19 11:28:26', '2023-01-19 11:28:38' ],
];

$date_times = [];

foreach ($input as $item) {
    $date_times[] = [ 'time' => $item[0], 'isStart' => true ];
    $date_times[] = [ 'time' => $item[1], 'isStart' => false ];
}

usort($date_times, fn($item1, $item2) => $item1['time'] <=> $item2['time']);

$count = 0;
$max = 0;
$result = [];   // can be omitted if not needed

for ($i = 0; $i < count($date_times); $i++) {
    $count = $date_times[$i]['isStart'] ? $count + 1 : $count - 1;
    $max = max($max, $count);
    $result[] = $count;   // can be omitted if not needed
}

echo "$max\n";
print_r($result);   // can be omitted if not needed

输出量:

Max: 5
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 2
    [4] => 1
    [5] => 2
    [6] => 3
    [7] => 4
    [8] => 3
    [9] => 4
    [10] => 3
    [11] => 2
    [12] => 1
    [13] => 2
    [14] => 3
    [15] => 2
    [16] => 1
    [17] => 2
    [18] => 1
    [19] => 2
    [20] => 3
    [21] => 4
    [22] => 5
    [23] => 4
    [24] => 3
    [25] => 2
    [26] => 3
    [27] => 4
    [28] => 3
    [29] => 2
    [30] => 1
    [31] => 2
    [32] => 1
    [33] => 0
)

相关问题