16

执行以下操作是否更快:

 if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') { ... }

或者:

 if (!in_array($var, array('test1', 'test2', 'test3', 'test4') { ... }

是否有许多值,在这一点上做一个或另一个更快?

(在这种情况下,第二个选项中使用的数组并不存在。)

4

10 回答 10

18

我强烈建议只使用in_array(),任何速度差异都可以忽略不计,但是单独测试每个变量的可读性是可怕的。

只是为了好玩,这是我运行的一个测试:

$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
$end = microtime(true);

print "Time1: ". ($end - $start)."<br />";

$start2 = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    if (!in_array($var, $array) ) {}
}
$end2 = microtime(true);

print "Time2: ".($end2 - $start2)."<br />";

// Time1: 1.12536692619
// Time2: 1.57462596893

需要注意的一点微不足道的注意事项,如果$var未设置,方法 1 需要更长的时间(取决于您测试的条件数)

更新较新的 PHP 版本:

Martijn:我已经将数组扩展为五个元素,并寻找test3,作为一种平均情况。

PHP5.6

Time1: 0.20484399795532
Time2: 0.29854393005371

PHP7.1

Time1: 0.064045906066895
Time2: 0.056781053543091

PHP7.4

Time1: 0.048759937286377
Time2: 0.049691915512085

PHP8.0

Time1: 0.045055150985718
Time2: 0.049431085586548

结论:原始测试不是最好的测试,而且:在 php7+ 中已成为偏好问题。

于 2008-11-27T21:21:51.790 回答
9

请注意,如果您要替换一堆!==语句,则应将第三个参数传递给in_arrayas true,这会强制对数组中的项目进行类型检查。

普通!=的显然不需要这个。

于 2008-11-28T01:43:02.167 回答
6

第一个会更快 - 第二个有很多开销:创建数组,调用函数,搜索数组......

然而,正如我在几个答案中所说的那样,过早优化是万恶之源。您应该编写可读的代码,然后如果需要对其进行优化,则对其进行优化。

编辑:

我对@Owen 的代码(PHP 5.2.6 / windows)的时间安排:

Time1: 1.33601498604
Time2: 4.9349629879

在循环内移动数组(...),如问题所示:

Time1: 1.34736609459
Time2: 6.29464697838
于 2008-11-27T21:22:13.070 回答
5

这是该板凳的实时更新与另一个案例https://3v4l.org/OA2S7

PHP 7.3 的结果:

  • 多重比较:0.0575 07991790771

  • in_array: 0.0256 8507194519

  • array_flip() 外循环测量 + isset(): 0.0146 78001403809

  • array_flip() 外部循环未测量 + isset(): 0.0156 50033950806

  • foreach 和比较:0.0627 82049179077

于 2019-03-18T18:19:36.177 回答
3

嗨,我只是将这种情况发挥到了极致,并指出随着值数量的增加,简单的比较并不是最有效的方式。

这是我的代码:

$var = 'test';
$num_values = 1000;
$iterations = 1000000;
print "\nComparison performance test with ".$num_values." values and ".$iterations." loop iterations";
print "\n";

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    if ($var != 'test0' &&
        $var != 'test1' &&
        // ...
        // yes I really have 1000 lines in my file
        // ...
        $var != 'test999') {}
}
print "\nCase 1: plain comparison";
print "\nTime 1: ". (microtime(true) - $start);
print "\n";

$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
    $array1[] = 'test'.$i;
}
for($i = 0; $i < $iterations; ++$i) {
    if (!in_array($var, $array1) ) {}
}
print "\nCase 2: in_array comparison";
print "\nTime 2: ".(microtime(true) - $start);
print "\n";

$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
    $array2['test'.$i] = 1;
}
for($i = 0; $i < $iterations; ++$i) {
    if (!isset($array2[$var])) {}
}
print "\nCase 3: values as keys, isset comparison";
print "\nTime 3: ".(microtime(true) - $start);
print "\n";

$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
    $array3['test'.$i] = 1;
}
for($i = 0; $i < $iterations; ++$i) {
    if (!array_key_exists($var, $array3)) {}
}
print "\nCase 4: values as keys, array_key_exists comparison";
print "\nTime 4: ".(microtime(true) - $start);
print "\n";

我的结果(PHP 5.5.9):

Case 1: plain comparison
Time 1: 31.616894006729

Case 2: in_array comparison
Time 2: 23.226133823395

Case 3: values as keys, isset comparison
Time 3: 0.050863981246948

Case 4: values as keys, array_key_exists comparison
Time 4: 0.13700890541077

我同意,这有点极端,但它展示了 PHP 的类哈希表关联数组的大局和巨大潜力,你只需要使用它

于 2014-12-11T08:52:40.823 回答
2

in_array 对于大量项目会更快。基于与数据和您的计算机相关的许多因素,“大”是非常主观的。既然您在问,我假设您处理的项目数量并不多。对于较长的列表,请注意此信息,并使用翻转数组来衡量性能,以便 php 可以利用散列查找而不是线性搜索。对于“静态”数组,调整可能不会提高性能,但也可能。

使用 Owen 的测试代码,使用翻转数组和更多迭代以获得更一致的结果:

$array2 = array_flip($array);
$iterations = 10000000;

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    if (!isset($array2[$var])) {}
}
$end = microtime(true);
print "Time3: ".($end - $start)."<br />";

Time1: 12.875
Time2: 13.7037701607
Time3: 3.70514011383
于 2008-11-27T21:26:04.230 回答
1

请注意,正如 RoBorg 指出的那样,创建数组有开销,因此应该在迭代循环内移动它。出于这个原因,Sparr 的帖子也有点误导,因为 array_flip 函数存在开销。

这是另一个包含所有 5 种变体的示例:

$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
   if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
print "Time1: ". (microtime(true) - $start);

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
   if (!in_array($var, $array) ) {}
}
print "Time2: ".(microtime(true) - $start);

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
   if (!in_array($var, array('test1', 'test2', 'test3', 'test4')) ) {}
}
print "Time2a: ".(microtime(true) - $start);

$array2 = array_flip($array);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
  if (!isset($array2[$var])) {}
}
print "Time3: ".(microtime(true) - $start);

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    $array2 = array_flip($array);
  if (!isset($array2[$var])) {}
}
print "Time3a: ".(microtime(true) - $start);

我的结果:

Time1 : 0.59490108493 // straight comparison
Time2 : 0.83790588378 // array() outside loop - not accurate
Time2a: 2.16737604141 // array() inside loop
Time3 : 0.16908097267 // array_flip outside loop - not accurate
Time3a: 1.57209014893 // array_flip inside loop

总之,使用array_flip(with isset) 比 inarray 快,但不如直接比较快。

于 2009-02-16T04:04:50.407 回答
1

当谈到 PHP,并询问是否:

  • 一组 "if" 和 "else ifs" ,
  • 带有一组“或”条件的“如果”(如原始帖子详细信息中所示),或
  • 将“in_array”与动态构造的数组一起使用,

更好,

应该记住,PHP 语言“switch”语句是为这种情况设计的替代方法,可能是更好的答案。(虽然张贴者的例子让我们只比较两个解决方案,但实际的问题标题要求考虑 in_array 与 PHP 语句,所以我认为这是公平的游戏)。

那么,在海报的示例中,我建议:

switch ($var)
{ case 'test1': case 'test2': case 'test3': case 'test4':
     echo "We have a good value"; break;
  default:
     echo "We do not have a good value";
}

我希望 PHP 在这种情况下允许使用几个非原始构造,例如“或”的逗号。但是上面是 PHP 的设计者认为是处理这个问题的最清晰的方法。而且它在执行时似乎也比其他两种选择更有效。

只要我说的是愿望清单,在 SQL 中找到的“IN”对于发布者的示例情况会更加清晰。

这种想法可能是导致人们想要在这种情况下使用“in_array”的原因,但不幸的是必须构建一个数据结构,然后使用为该数据结构设计的谓词,而不是有办法只在没有发生这种开销的情况下说出来。

于 2015-06-21T20:12:21.017 回答
0

我知道这个问题已经有将近 10 年的历史了,但是还有其他方法可以做到这一点。我使用了Nick 页面中的方法 B,其中包含数千个条目。它非常快。

foreach(array_values($haystack) as $v)
    $new_haystack[$v] = 1; 
}

// So haystack becomes:
$arr[“String1”] = 1;
$arr[“String2”] = 1;
$arr[“String3”] = 1;


// Then check for the key:
if (isset($haystack[$needle])) {
    echo("needle ".$needle." found in haystack");
}
于 2017-08-27T07:52:56.363 回答
0

我的测试

$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
$end = microtime(true);

print "Time1: ". ($end - $start)."<br />";

$start2 = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    if (!in_array($var, $array) ) {}
}
$end2 = microtime(true);

print "Time2: ".($end2 - $start2)."<br />";

$array_flip = array_flip($array);

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    if (!isset($array_flip[$var])) {}
}
$end = microtime(true);
print "Time3: ".($end - $start)."<br />";

$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
    if (!isset($array[$var])) {}
}
$end = microtime(true);

print "Time4: ". ($end - $start)."<br />";

时间1:0.20001101493835

时间2:0.32601881027222

时间3:0.072004079818726

时间4:0.070003986358643

于 2019-02-08T23:31:23.740 回答