Question

Est-il plus rapide de procéder comme suit:

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

Ou:

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

Y a-t-il un certain nombre de valeurs auxquelles il est plus rapide de faire l'une ou l'autre?

(Dans ce cas, le tableau utilisé dans la deuxième option n'existe pas déjà.)

Était-ce utile?

La solution

Je suggérerais fortement d'utiliser in_array () , toute différence de vitesse serait négligeable, mais la lisibilité de tester chaque variable séparément est horrible.

juste pour le plaisir, voici un test que j'ai couru:

$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

remarque un peu triviale à surveiller, si $ var n'est pas défini, la méthode 1 prend beaucoup plus de temps (en fonction du nombre de conditions que vous testez)

Autres conseils

Notez que si vous souhaitez remplacer un ensemble d'instructions ! == , vous devez passer le troisième paramètre à in_array sous la forme true , ce qui impose la vérification du type des éléments du tableau.

Ordinary ! = ne l'exige évidemment pas.

Le premier sera plus rapide - le second est surchargé: créer le tableau, appeler une fonction, rechercher dans le tableau ...

Cependant, comme je l’ai dit dans une question à quelques réponses, l’optimisation prématurée est la racine de tous les maux. Vous devez écrire votre code pour qu'il soit lisible, puis si il doit être optimisé, profilez-le, puis optimisez-le.

Modifier:

Mes timings avec le code de @ Owen (PHP 5.2.6 / windows):

Time1: 1.33601498604
Time2: 4.9349629879

Déplacement du tableau (...) dans la boucle, comme dans la question:

Time1: 1.34736609459
Time2: 6.29464697838

in_array sera plus rapide pour un grand nombre d’éléments. " grand " être très subjectif sur la base de nombreux facteurs liés aux données et à votre ordinateur. Puisque vous posez la question, je suppose que vous ne traitez pas un nombre trivial d’articles. Pour les listes plus longues, tenez compte de cette information , et mesurer les performances avec un tableau retourné afin que php puisse utiliser des recherches de hachage au lieu d'une recherche linéaire. Pour un " statique " Un tableau qui ne permet pas d’améliorer les performances, mais peut aussi.

Utilisation du code de test d'Owen, avec un tableau retourné et plusieurs itérations pour des résultats plus cohérents:

$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

Bonjour, je viens de pousser le cas à l'extrême et de souligner qu'avec un nombre croissant de valeurs, la comparaison simple n'est pas la méthode la plus performante.

Voici mon code:

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

Mes résultats (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

Je suis d’accord, c’est un peu extrême, mais cela montre la situation dans son ensemble et le grand potentiel des tableaux associatifs en PHP de type table de hachage, il vous suffit de l’utiliser

Notez que, comme RoBorg l’a souligné, la création du tableau nécessite un temps système et doit donc être déplacé à l’intérieur de la boucle d’itération. Pour cette raison, le message de Sparr est également un peu trompeur car il y a un surcoût avec la fonction array_flip.

Voici un autre exemple avec les 5 variantes:

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

Mes résultats:

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 résumé, l'utilisation de array_flip (avec isset) est plus rapide que inarray mais pas aussi rapide qu'une comparaison simple.

Quand on parle de PHP et qu'on demande si:

  • un ensemble de "si" et de "sinon si" ,
  • an " if " avec un ensemble de conditions "ou" (comme dans les détails de la publication d'origine), ou
  • utilisation de " in_array " avec un tableau construit à la volée,

est meilleur,

il ne faut pas oublier que le langage PHP " switch " déclaration est une alternative conçue pour de telles situations et peut être une meilleure réponse. (Bien que l'exemple de l'affiche nous amène à ne comparer que deux solutions, l'en-tête de la question demande de considérer les déclarations in_array par rapport aux déclarations PHP, donc je pense que c'est un jeu équitable.)

Dans l'exemple de l'affiche, je recommanderais plutôt:

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

Je souhaite que PHP autorise une ou deux constructions non primitives, telles qu'une virgule pour "ou". Mais ce qui précède est ce que les concepteurs de PHP ont considéré comme le moyen le plus clair de gérer cela. Et il semble être plus efficace au moment de l’exécution que les deux autres alternatives.

Tant que je parle d'une liste de souhaits, le " IN " trouvé dans SQL serait encore plus clair pour l'exemple de la situation de l'affiche.

Cette pensée est probablement ce qui pousse les gens à vouloir utiliser "in_array" dans de telles situations, mais il est malheureux de devoir créer une structure de données puis d'utiliser un prédicat conçu pour cette structure de données, plutôt que d'avoir une façon de le dire sans que cela ne se produise.

Voici une mise à jour en direct de ce banc avec une autre affaire https://3v4l.org/OA2S7

Les résultats pour PHP 7.3:

  • comparaisons multiples: 0,0575 07991790771

  • in_array: 0,0256 8507194519

  • array_flip () boucle extérieure mesurée + isset (): 0.0146 78001403809

  • array_flip () boucle extérieure non mesurée + isset (): 0.0156 50033950806

  • Recherche et comparaison: 0,0627 82049179077

Je sais que cette question a presque 10 ans, mais il existe d'autres moyens de le faire. J'ai utilisé la méthode B de la de la page de Nick avec des milliers d'entrées. C'était incroyablement rapide.

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

Mes tests

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

Heure1: 0.20001101493835

     

Time2: 0.32601881027222

     

Heure3: 0.072004079818726

     

Time4: 0.070003986358643

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top