1

我有大型索引数组,其中数组元素可以在 1 到 2*10^5 之间变化,并且 php 函数超出 Max_execution_timeout。如何在不直接更改任何其他文档的情况下使其快速或使其正常工作(如果有一种方法可以使函数内的执行时间更多)。功能与小块数据正常工作。

这是附件https://drive.google.com/file/d/1egyzLQWV69IDKjbMzS1ZG3e-bPy3qjjM/view?usp=sharing

<?php
 // $count = array of element

function activityNotifications($expenditure, $d) {

    $size = sizeof($expenditure);
    $count = 0 ;
    for($i=0;$i<$size-$d;$i++){
        $median = array();
        for($k=0;$k<$d;$k++){ 
            $median[$k] = $expenditure[$i+$k];
        }
        sort($median);

        if($d%2 == 1){
            $middle = $median[floor($d/2)];
        } else if($d%2 == 0){ 
            $value = $d/2;
            $middle = $median[$value] + $median[$value-1];
            $middle = $middle/2;
        }
        $value = $middle*2;

        if($value<=$expenditure[$d+$i]){
            $count++;
        }
    }
    return $count;
}

echo activityNotifications($count2,$d);

?>
4

2 回答 2

0

由于$d在此函数中充当常量,因此一般改进是在循环外提取固定数据。

我认为重要的部分是声明$median一次,然后重用它,这可能会减少一些 GC 开销。

function activityNotifications($expenditure, $d)
{
    $size = sizeof($expenditure);
    $count = 0 ;
    $median = array_fill(0, $d, 0); #create an array with predefined size
    $d_divide_by_2 = $d/2;
    $d_divide_by_2_int = floot($d_divide_by_2);

    if($d%2 == 1)
    {
        for($i=0;$i<$size-$d;$i++)
        {
            for($k=0;$k<$d;$k++)
            { 
                $median[$k] = $expenditure[$i+$k];
            }
            sort($median);

            $value = $median[$d_divide_by_2_int]*2;

            if($value<=$expenditure[$d+$i]){
                $count++;
            }
        }
    }
    else
    {
        for($i=0;$i<$size-$d;$i++)
        {
            for($k=0;$k<$d;$k++)
            { 
                $median[$k] = $expenditure[$i+$k];
            }
            sort($median);

            $value = $median[$d_divide_by_2] + $median[$d_divide_by_2-1];

            if($value<=$expenditure[$d+$i]){
                $count++;
            }
        }
    }

    return $count;
}
于 2019-01-16T14:37:35.403 回答
0

一些提高性能的建议是:

代替:

for($k=0;$k<$d;$k++){ 
    $median[$k] = $expenditure[$i+$k];
}

利用:

$median = array_slice($expenditure, $i, $d);

一般来说,数组函数会比循环更快。

另一个不同的想法是降低sort()函数的成本。您可以通过维护$median大部分排序的数组来做到这一点。因此,不是每次都取一个切片,而是将一个值推入并拉出一个值。就像是:

$median[$i+$d] = $expenditure[$i+$d]; // append a value
unset($median[$i]); // remove a value

然后用于asort排序和维护键关联:

asort($median);

本质$median上将始终是$expenditure大小为 d 的窗口,并保持关键关联。您可以$median从一开始就初始化您的切片,首先使用:$median = array_slice($expenditure, $i, $d);在循环之外。

非常粗略(我自己没有测试过):

function activityNotifications($expenditure, $d) {

    $size = sizeof($expenditure);
    $count = 0 ;
    $median = array_slice($expenditure, 0, $d, TRUE); // initial slice with keys
    for($i=$d;$i<$size;$i++){

        $median[$i]=$expenditure[$i];
        unset($median[$i-$d]);
        asort($median);

        $median_values = array_values($median);
        if($d%2 == 1){
            $middle = $median_values[floor($d/2)];
        } else if($d%2 == 0){ 
            $value = $d/2;
            $middle = $median_values[$value] + $median_values[$value-1];
            $middle = $middle/2;
        }
        $value = $middle*2;

        if($value<=$expenditure[$d+$i]){
            $count++;
        }
    }
    return $count;
}

请注意,上面的代码不能直接工作,因为当您提取中点值时,键不会按顺序排列。所以你可能需要先使用array_values(我在上面添加了这个)。

于 2019-01-16T16:59:04.857 回答