Pregunta

¿Es más rápido hacer lo siguiente?

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

O:

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

¿Hay varios valores en qué punto es más rápido hacer uno u otro?

(En este caso, la matriz utilizada en la segunda opción ya no existe).

¿Fue útil?

Solución

Sugeriría encarecidamente usar in_array () , cualquier diferencia de velocidad sería insignificante, pero la legibilidad de probar cada variable por separado es horrible.

solo por diversión, aquí hay una prueba que ejecuté:

$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 ligeramente trivial a tener en cuenta, si $ var no está configurado, el método 1 lleva mucho más tiempo (dependiendo de cuántas condiciones pruebe)

Otros consejos

Tenga en cuenta que si está buscando reemplazar un montón de declaraciones ! == , debe pasar el tercer parámetro a in_array como true , que exige la verificación de tipos en los elementos de la matriz.

Ordinary ! = no requiere esto, obviamente.

El primero será más rápido: el segundo tiene muchos gastos generales: crear la matriz, llamar a una función, buscar en la matriz ...

Sin embargo, como dije en una pregunta con un par de respuestas, la optimización prematura es la raíz de todo mal. Debe escribir su código para que sea legible, luego si necesita ser optimizado, perfílelo, luego optimícelo.

Editar:

Mis tiempos con el código de @ Owen (PHP 5.2.6 / windows):

Time1: 1.33601498604
Time2: 4.9349629879

Mover la matriz (...) dentro del bucle, como en la pregunta:

Time1: 1.34736609459
Time2: 6.29464697838

in_array será más rápido para grandes cantidades de elementos. " grande " siendo muy subjetivo basado en muchos factores relacionados con los datos y su computadora. Como está preguntando, supongo que no está tratando con un número trivial de artículos. Para listas más largas, preste atención a esta información , y mida el rendimiento con una matriz volteada para que php pueda utilizar búsquedas hash en lugar de una búsqueda lineal. Para una " estática " matriz que ajustar puede no mejorar el rendimiento, pero también puede.

Usando el código de prueba de Owen, con una matriz invertida y más iteraciones para obtener resultados más 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

Hola, acabo de llevar este caso a extremos y señalé que con un número creciente de valores, la comparación simple no es la forma más eficaz.

Aquí está mi 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";

Mis 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

Estoy de acuerdo, eso es un poco extremo, pero muestra el panorama general y el gran potencial en las matrices asociativas tipo PHP de tabla hash, solo tiene que usarlo

Tenga en cuenta que, como señaló RoBorg, hay una sobrecarga en la creación de la matriz, por lo que debe moverse dentro del ciclo de iteración. Por esta razón, la publicación de Sparr también es un poco engañosa ya que hay una sobrecarga con la función array_flip.

Aquí hay otro ejemplo con las 5 variaciones:

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

Mis 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

En resumen, usar array_flip (con isset) es más rápido que una matriz pero no tan rápido como una comparación directa.

Al hablar de PHP y preguntar si:

  • un conjunto de '' if '' sy '' else ifs '' ,
  • un " if " con un conjunto de condiciones editadas (como en los detalles de la publicación original), o
  • uso de " en_array " con una matriz construida sobre la marcha,

es mejor,

hay que tener en cuenta que el lenguaje PHP "cambia" La declaración es una alternativa diseñada para tales situaciones y puede ser una mejor respuesta. (Aunque el ejemplo del póster nos lleva a comparar solo dos soluciones, el encabezado de la pregunta real requiere considerar las declaraciones in_array versus PHP, así que creo que este es un juego justo).

En el ejemplo del póster, recomendaría:

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

Desearía que PHP permitiera un par de construcciones no primitivas en los casos, como una coma para '' o ''. Pero lo anterior es lo que los diseñadores de PHP consideran la forma más clara de manejar esto. Y parece ser más eficiente en tiempo de ejecución que las otras dos alternativas, también.

Mientras esté hablando de una lista de deseos, el " IN " encontrado en SQL sería aún más claro para la situación de ejemplo del póster.

Este pensamiento es probablemente lo que lleva a las personas a querer usar `` in_array '' para tales situaciones, pero es desafortunado tener que construir una estructura de datos y luego usar un predicado diseñado para esa estructura de datos, en lugar de tener una manera de decirlo sin que ocurra esa sobrecarga.

Aquí hay una actualización en vivo de este banco con otro caso https://3v4l.org/OA2S7

Los resultados para PHP 7.3:

  • comparaciones múltiples: 0.0575 07991790771

  • en_array: 0.0256 8507194519

  • array_flip () fuera del ciclo medido + isset (): 0.0146 78001403809

  • array_flip () lazo externo no medido + isset (): 0.0156 50033950806

  • foreach y comparación: 0.062782049179077

Sé que esta pregunta tiene casi 10 años, pero hay otras formas de hacerlo. Usé el método B de la página de Nick con miles de entradas. Fue increíblemente 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");
}

Mis pruebas

$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: 0.20001101493835

     

Time2: 0.32601881027222

     

Time3: 0.072004079818726

     

Time4: 0.070003986358643

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top