Pergunta

É mais rápido para fazer o seguinte:

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

Ou:

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

Existe um número de valores em que ponto ele é mais rápido para fazer um ou o outro?

(Neste caso, a matriz utilizada na segunda opção não existe alreay.)

Foi útil?

Solução

i sugiro fortemente apenas usando in_array(), qualquer diferença de velocidade seria insignificante, mas a legibilidade do teste de cada variável separadamente é horrível.

apenas para se divertir aqui está um teste eu corri:

$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

nota ligeiramente trivial para assistir, se $var não está definido, o método 1 leva muito mais tempo (dependendo de quantas condições que você teste)

Outras dicas

Note que se você está olhando para substituir um monte de declarações !==, você deve passar o terceiro parâmetro para in_array como true, que impõe a verificação de tipo sobre os itens na matriz.

!= Ordinária não requer isso, obviamente.

O primeiro será mais rápido - o segundo tem um monte de sobrecarga: a criar a matriz, chamar uma função, procurando a matriz ...

No entanto, como eu disse em uma pergunta de um par de respostas para baixo, otimização prematura é a raiz de todo o mal. Você deve escrever seu código para ser legível, em seguida, se que precisa ser otimizado perfil que, em seguida, otimizar.

Editar:

Os meus horários com @ código de Owen (PHP 5.2.6 / Windows):

Time1: 1.33601498604
Time2: 4.9349629879

Movendo a matriz (...) dentro do circuito, como na pergunta:

Time1: 1.34736609459
Time2: 6.29464697838

in_array será mais rápido para um grande número de itens. "Grande" sendo muito subjetiva com base em uma série de fatores relacionados aos dados e seu computador. Desde que você está pedindo, eu suponho que você não está lidando com um número trivial de itens. Para listas mais longas, atenção esta informação , e medir o desempenho com uma matriz invertida para que php pode utilizar pesquisas de hash em vez de uma pesquisa linear. Para uma matriz "estático" que emenda não pode melhorar o desempenho, mas também pode.

Usando o código de teste de Owen, com uma matriz invertida e mais iterações para resultados mais consistentes:

$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

Oi eu só tomou neste caso a extremos e apontou que com o aumento do número de valores de comparação simples é não a maneira mais performance.

Aqui está o meu código:

$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";

Os meus resultados (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

Eu concordo, isso é um pouco exagerado, mas mostra o retrato grande e o grande potencial na mesa-de hash-like arrays associativos de PHP, você apenas tem que usá-lo

Note-se que como RoBorg salientou, há sobrecarga na criação da matriz de modo que deve ser movido no interior do circuito de iteração. Por esta razão, o post de Sparr também é um pouco enganador como há sobrecarga com a função array_flip.

Aqui está outro exemplo com todas as 5 variações:

$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);

Meus resultados:

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

Em resumo, usando array_flip (com isset) é mais rápido que inarray mas não tão rápido como uma comparação em linha reta.

Quando se fala de PHP, e perguntando se:

  • um conjunto de "se" s e "ses else",
  • um "se" com um conjunto de "ou" condições ed (como nos detalhes post original), ou
  • uso de "in_array" com um on-the-fly série construída,

é melhor,

deve-se ter em mente que a linguagem PHP declaração "switch" é uma alternativa concebida para tais situações e pode ser uma resposta melhor. (Apesar de exemplo leads do cartaz dos EU para apenas comparando duas soluções, o título questão real pede para considerar in_array contra declarações PHP, então eu acho que isso é um jogo justo).

No exemplo do cartaz, então, eu, em vez de recomendar:

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";
}

Desejo PHP permitido por um par de construções não-primitivos nos casos, como uma vírgula para "ou". Mas o acima é o que os designers do PHP considerada a maneira mais clara de lidar com isso. E parece ser mais eficiente em tempo de execução do que as outras duas alternativas, também.

Enquanto eu estou falando de uma lista, o "IN" encontrada no SQL seria ainda mais clara, por exemplo, a situação do cartaz.

Este pensamento é provavelmente o que leva as pessoas que querem usar "in_array", para tais situações, mas é tipo de triste ter que construir uma estrutura de dados e, em seguida, usar um predicado projetado para que a estrutura de dados, em vez de ter um maneira de apenas dizer que sem isso acontecer em cima.

Aqui está uma atualização ao vivo do banco com um outro caso https://3v4l.org/OA2S7

Os resultados para PHP 7.3:

  • comparações múltiplas: 0,0575 07991790771

  • in_array: 0,0256 8507194519

  • array_flip () fora circuito medido + isset (): 0,0146 78001403809

  • array_flip () loop externo não medido + isset (): 0,0156 50033950806

  • foreach e comparação: 0,0627 82049179077

Eu sei que esta pergunta é quase 10 anos, mas há outras maneiras de fazer isso. Eu usei o método B de página de Nick com milhares de entradas. Foi incrivelmente rápido.

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");
}

Meu Testing

$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 />";

Time1: ,20001101493835

Time2: ,32601881027222

time3: ,072004079818726

time4: ,070003986358643

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top