Что быстрее: in_array() или куча выражений в PHP?
Быстрее сделать следующее:
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') { ... }
Или:
if (!in_array($var, array('test1', 'test2', 'test3', 'test4') { ... }
Есть ли несколько значений, в которые он быстрее выполняет одно или другое?
(В этом случае массив, используемый во втором варианте, не существует.)
Ответы
Ответ 1
Я бы настоятельно предложил просто использовать 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 занимает гораздо больше времени (в зависимости от того, сколько условий вы проверяете)
Ответ 2
Обратите внимание, что если вы хотите заменить кучу операторов !==
, вы должны передать третий параметр in_array
как true
, который обеспечивает проверку типов элементов в массиве.
Обычный !=
не требует этого, очевидно.
Ответ 3
Первый будет быстрее - второй имеет много накладных расходов: создание массива, вызов функции, поиск массива...
Однако, как я сказал в вопросе пару ответов, преждевременная оптимизация - это корень всего зла. Вы должны написать свой код для чтения, а затем, если он нуждается в оптимизации профиля, затем оптимизируйте.
Edit:
Мои тайминги с кодом @Owen (PHP 5.2.6/windows):
Time1: 1.33601498604
Time2: 4.9349629879
Перемещение массива (...) внутри цикла, как в вопросе:
Time1: 1.34736609459
Time2: 6.29464697838
Ответ 4
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
Ответ 5
Обратите внимание, что, как указал 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
(с isset) выполняется быстрее, чем inarray, но не так быстро, как прямое сравнение.
Ответ 6
Привет, я просто перевел этот случай в крайности и отметил, что с увеличением числа значений простое сравнение не наиболее действенное.
Вот мой код:
$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, вам просто нужно использовать его
Ответ 7
Говоря о PHP и спрашивая:
- набор "if" и "else ifs",
- "if" с набором "или" условий ed (как в исходных деталях сообщения) или
- использование "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" для таких ситуаций, но, к сожалению, нужно создавать структуру данных, а затем использовать предикат, предназначенный для этой структуры данных, а не иметь способ просто сказать это без этих накладных расходов.
Ответ 8
Я знаю, что этот вопрос почти 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");
}