Вопрос

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

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

Или:

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

Существует ли ряд значений, в какой момент быстрее выполнить то или иное?

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

Это было полезно?

Решение

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

Другие советы

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

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

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

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

Редактировать:

Мои тайминги с кодом @Owen (PHP 5.2.6 / Windows):

Time1: 1.33601498604
Time2: 4.9349629879

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

Time1: 1.34736609459
Time2: 6.29464697838

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

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

Вот мой код:

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

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

Говоря о PHP и спрашивая, является ли:

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

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

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

Вот оперативное обновление этого стенда с другим случаем https://3v4l.org/OA2S7

Результаты для PHP 7.3:

  • множественные сравнения: 0.057507991790771

  • в_array: 0.02568507194519

  • array_flip() измеренный внешний цикл + isset(): 0.014678001403809

  • array_flip() внешний цикл не измерен + isset(): 0.015650033950806

  • предварительный поиск и сравнение: 0.062782049179077

Я знаю, что этому вопросу почти 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");
}

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

$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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top