这是假设的代码,假设我有以下内容:
假设我有一个数组,它有很多数据,在这个示例问题中是整数,但它可以是任何类型的数据,这些数据已经按照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;
}
}