5

这是假设的代码,假设我有以下内容:

假设我有一个数组,它有很多数据,在这个示例问题中是整数,但它可以是任何类型的数据,这些数据已经以某种方式就 if 语句进行了排序。

$a = array(0,0,0,1,1,1,1,1,1,2,2,2,2,3,3,...,9,9,9);

假设我有一个带有许多 if else if 语句的 for 循环,这些语句可以有任何标准来做某事。

for($i=0; i<count($a); i++) {
    // these if statements can be anything and may or may not be related with $a
    if($a[$i] == 0 && $i < 10) { 
        // do something
    }
    else if($a[$i] == 1 && $i < 20) {
        // do something
    }
    else if($a[$i] == 2) {
        // do something
    }
    else if($a[$i] == 3) {
        // do something
    }

    // and so on
}

现在的问题是,在第一个 if 语句迭代完成后,它从未使用过。一旦 for 循环开始使用下一个 if 语句,就不需要再次评估前一个 if 语句。它可以使用第一个 if 语句 n 次等等。

有没有办法对其进行优化,这样它就不必遍历所有前面的 if else if 语句,因为它正在循环数据?请注意,数据可以是任何东西,if 语句可以是各种条件。

是否存在我看不到的范式转变,这对于如何编码以提供最佳性能是必需的?

4

7 回答 7

1

我认为你在转动你的轮子。

如果您有大量数据,很可能,速度慢来自数据源而不是服务器端计算。

如果你做任何事情,你应该将你的数据分解成块并一次运行部分。只有当您注意到服务器上的加载时间缓慢或顶部负载不佳时,您才需要这样做。

异步连接允许您轻松地执行此操作,使用 ajax 您可以连接到服务器,提取有限的数据块,处理它,然后在客户端浏览器中显示之后,运行下一个块。每当您使用查询大量数据的网站(即:facebook)时,它都会这样做。

但同样,不要过度思考这一点。你真的不需要让你的程序更复杂。如果您真的想要一个金星,您可以创建一个面向对象的类来为您处理所有这些,但我不会深入探讨。

于 2013-08-19T20:17:40.057 回答
1

你可以利用call_user_func_array. 您需要构建一个类来存储要调用的方法以执行语句。考虑这样一个类:

class MyStatements {
    public function If0($a, $i) {
        if($a[$i] == 0 && $i < 10) {
            // do something
        }
    }

    public function If1($a, $i) {
        if($a[$i] == 1 && $i < 20) {
            // do something
        }
    }
}

然后你可以做这样的事情:

$stmts = new MyStatements();
for($i = 0; i < count($a); i++) {
    call_user_func_array(array($stmts, 'If' . strval($i)), array($a, $i));
}
于 2013-08-19T20:10:35.553 回答
0

这个详细的解决方案将阻止任何if条件在其评估为 false 后运行,并且不会多次迭代相同的$i值,除非它转换到下一个循环。

for($i=0; i<count($a); i++) {
    if($firstCondition) {
        //do something
    } else {
        break;
    }
}

for($i; i<count($a); i++) {
    if($secondCondition) {
        //do something
    } else {
        break;
    }
}
于 2013-08-19T22:52:00.743 回答
0

将你的 for 语句分解为多个 for 语句。对于您的示例代码:

for($i=0; i<10; i++) {
    if($a[$i] == 0) {
        //do something
    }
}

for($i=0; i<20; i++) {
    if($a[$i] == 1) {
        //do something
    }
}

for($i=0; $i<count($a); $i++) {
    if($a[$i] == 2) {
        // do something
    }
    else if($a[$i] == 3) {
        // do something
    }
}

//etc...
于 2013-08-19T20:03:42.997 回答
0

如果您使用的是 PHP 5.3+,那么您可以使用匿名函数

$a = array(0,0,0,1,1,1,1,1,1,2,2,2,2,3,3,9,9,9);

$dispatch = array(
    0=>function() { echo "0"; },
    1=>function() { echo "1"; },
    2=>function() { echo "2"; },
    3=>function() { echo "3"; },
    9=>function() { echo "9"; }
);

foreach ($a as $i)
{
    $dispatch[$i]();
}

在 PHP 5.3 之前,您必须使用映射到函数名称,但底部也适用于 PHP 5.3+。

$a = array(0,0,0,1,1,1,1,1,1,2,2,2,2,3,3,9,9,9);

function foo0()  { echo "0"; }
function foo1()  { echo "1"; }
function foo2()  { echo "2"; }
function foo3()  { echo "3"; }
function foo9()  { echo "9"; }

$dispatch = array(
    0=>"foo0",
    1=>"foo1",
    2=>"foo2",
    3=>"foo3",
    9=>"foo9"
);

foreach ($a as $i)
{
    $dispatch[$i]();
}

上面的代码更快,但效率不高。为了提高性能,您必须在 $dispatch 数组中删除键查找,并在每次 $a[#] 的值更改时向前移动。这假设您的 $dispatch 数组与输入数组匹配。如果 $dispatch 数组非常大,您只会获得性能改进。

$a = array(0,0,0,1,1,1,1,1,1,2,2,2,2,3,3,9,9,9);

function foo0()  { echo "0"; }
function foo1()  { echo "1"; }
function foo2()  { echo "2"; }
function foo3()  { echo "3"; }
function foo9()  { echo "9"; }

$dispatch = array(
    0=>"foo0",
    1=>"foo1",
    2=>"foo2",
    3=>"foo3",
    9=>"foo9"
);

reset($dispatch);
$foo = (string)current($dispatch);
$last = 0;
foreach ($a as $i)
{
    $foo();
    if($i != $last)
    {
        $foo = (string)next($dispatch);
        $last = $i;
    }
}

这应该尽可能高效。

于 2013-08-19T20:51:26.250 回答
0

我不确定这与解决方案有什么不同,但我想我会把它扔在那里。

function func1 () {
    echo "hi\n";
}
function func2 () {
    echo "bye\n";
}
$functionList = array (
    0 => "func1",
    1 => "func2"
);
$a = array(0,0,0,1,1,1,1,1,1,2,2,2,2,3,3,9,9,9);
$len = count($a);
for($i = 0; $i < $len; $i++) {
    if (isset($functionList[$i])) {
        call_user_func($functionList[$i]);
    }
}

我明确设置了键$functionList,因为 OP 说它们并不总是数字。也许前 2-3 个作业可以打包成一个班级。

于 2013-08-19T20:51:30.353 回答
0

与许多其他现代语言一样,PHP 使用称为“短路评估”的东西。这意味着一旦布尔表达式被确定为真或假,表达式的其余部分将不会被计算。

因此,您可以引入新的布尔值(可能是它们的数组)来跟踪是否已经执行了一段代码,如果已经执行,则将其设置为 false。然后将此布尔值用作“if”表达式中的第一个条件。PHP 将识别该值设置为 false,并忽略该子句的其余部分。这是一条非常简单的路线,并且可以使您的代码大部分结构保持现在的状态。

于 2013-08-19T20:06:53.807 回答