Что быстрее: in_array () или куча выражений в PHP? - PullRequest
15 голосов
/ 28 ноября 2008

Быстрее ли сделать следующее:

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

Или:

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

Есть ли несколько значений, в которые момент быстрее делать одно или другое?

(В этом случае массив, используемый во втором параметре, уже не существует.)

Ответы [ 10 ]

16 голосов
/ 28 ноября 2008

Я бы настоятельно рекомендовал просто использовать 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 занимает намного больше времени (в зависимости от того, сколько условий вы тестируете)

7 голосов
/ 28 ноября 2008

Обратите внимание, что если вы хотите заменить кучу операторов !==, вам следует передать третий параметр в in_array как true, что обеспечивает проверку типа для элементов в массив.

Обычный != не требует этого, очевидно.

6 голосов
/ 28 ноября 2008

Первый будет быстрее - у второго много накладных расходов: создание массива, вызов функции, поиск в массиве ...

Однако, как я сказал в одном из нескольких ответов на вопрос, преждевременная оптимизация является корнем всего зла. Вы должны написать свой код, чтобы он был читабельным, затем , если , его нужно оптимизировать, профилировать его, а затем оптимизировать.

Edit:

Мои настройки с кодом @ Оуэна (PHP 5.2.6 / windows):

Time1: 1.33601498604
Time2: 4.9349629879

Перемещение массива (...) внутри цикла, как в вопросе:

Time1: 1.34736609459
Time2: 6.29464697838
2 голосов
/ 11 декабря 2014

Привет, я просто довел этот случай до крайности и указал, что с увеличением количества значений простое сравнение не самый эффективный способ.

Вот мой код:

$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, подобных хэш-таблицам, вы просто должны его использовать

2 голосов
/ 28 ноября 2008

in_array будет быстрее для большого количества предметов. «большой», будучи очень субъективным, зависит от множества факторов, связанных с данными и вашим компьютером. Поскольку вы спрашиваете, я предполагаю, что вы не имеете дело с тривиальным количеством предметов. Для более длинных списков обратите внимание на эту информацию и измерьте производительность с помощью перевернутого массива, чтобы php мог использовать поиск по хешу вместо линейного поиска. Для «статического» массива эта настройка не может улучшить производительность, но также может.

Использование тестового кода Оуэна, с перевернутым массивом и большим количеством итераций для более согласованных результатов:

$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
1 голос
/ 18 марта 2019

Вот живое обновление этой скамьи с другим делом 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

1 голос
/ 21 июня 2015

Говоря о PHP и спрашивая:

  • набор "if" и "else ifs",
  • «если» с набором условий «или» (как в оригинальных записях) или
  • использование "in_array" с массивом, созданным на лету,

лучше,

Следует иметь в виду, что оператор «switch» языка PHP является альтернативой, разработанной для таких ситуаций, и может быть лучшим ответом. (Хотя пример автора приводит нас к сравнению двух решений, фактический заголовок вопроса требует рассмотреть 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 сочли самым простым способом решения этой проблемы. И, похоже, он более эффективен во время выполнения, чем две другие альтернативы.

Пока я говорю о списке желаний, "IN", найденный в SQL, будет еще более понятным для примера примера плаката.

Это размышление, вероятно, приводит к тому, что люди хотят использовать "in_array" для таких ситуаций, но, к сожалению, приходится создавать структуру данных и затем использовать предикат, разработанный для этой структуры данных, а не иметь способ просто сказать это без каких-либо накладных расходов.

1 голос
/ 16 февраля 2009

Обратите внимание, что, как указал Роборг, создание массива связано с дополнительными затратами, поэтому его следует перемещать внутри цикла итерации. По этой причине пост Спарра также немного вводит в заблуждение, так как накладные расходы связаны с функцией 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 (с isset) быстрее, чем inarray, но не так быстро, как прямое сравнение.

0 голосов
/ 09 февраля 2019

Мое тестирование

$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

0 голосов
/ 27 августа 2017

Я знаю, что этому вопросу уже почти 10 лет, но есть и другие способы сделать это. Я использовал метод 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");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...