如何优化if-else-if语句,其中循环中没有使用以前的if


How to optimize an if else if statement where previous ifs are not used in loop?

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

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

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

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

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语句可以是任何各种条件。

在如何编码以提供最佳性能方面,是否需要进行我看不到的范式转变?

您可以利用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));
}

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

如果你有很多数据,那么速度慢很可能来自数据源,而不是服务器端的计算。

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

异步连接使您可以轻松地做到这一点,使用ajax,您可以连接到服务器,提取有限的数据块,进行处理,然后在客户端浏览器中显示后,运行下一个数据块。每当你使用一个查询大量数据的网站(例如:脸书)时,它都是这样做的。

不过,还是别想太多。你真的不需要让你的程序变得更复杂。如果你真的想要一颗金星,你可以制作一个面向对象的类,为你处理所有这些,但我不会深入讨论。

PHP和许多其他现代语言一样,使用一种叫做"短路求值"的方法。这意味着一旦布尔表达式被确定为true或false,就不会对表达式的其余部分进行求值。

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

将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...

如果您使用的是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;
    }
}

这应该是尽可能有效的。

我不确定这与解决方案有多大不同,但我想我会把它扔掉。

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个作业可以打包到一个班级里。

此详细解决方案将防止任何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;
    }
}