web-dev-qa-db-fra.com

qu'est-ce qui est plus rapide: in_array ou isset?

Cette question est simplement pour moi car j'aime toujours écrire du code optimisé qui peut aussi fonctionner sur des serveurs lents et pas chers (ou des serveurs avec BEAUCOUP de trafic)

J'ai regardé autour de moi et je n'ai pas pu trouver de réponse. Je me demandais ce qui est plus rapide entre ces deux exemples en gardant à l'esprit que les clés du tableau dans mon cas n'ont pas d'importance (pseudo-code naturellement):

<?php
$a = array();
while($new_val = 'get over 100k email addresses already lowercased'){
    if(!in_array($new_val, $a){
        $a[] = $new_val;
        //do other stuff
    }
}
?>

<?php
$a = array();
while($new_val = 'get over 100k email addresses already lowercased'){
    if(!isset($a[$new_val]){
        $a[$new_val] = true;
        //do other stuff
    }
}
?>

Puisque le point de la question n’est pas la collision de tableaux, je voudrais ajouter que si vous avez peur des collisions insérées pour $a[$new_value], Vous pouvez utiliser $a[md5($new_value)]. il peut toujours provoquer des collisions, mais éviterait une éventuelle attaque par déni de service lors de la lecture d'un fichier fourni par l'utilisateur ( http://nikic.github.com/2011/12/28/Supercolliding-a-PHP-array) .html )

88
Fabrizio

Les réponses à ce jour sont parfaites. Utiliser isset dans ce cas est plus rapide car

  • Il utilise une recherche de hash O(1) sur la clé alors que in_array doit vérifier chaque valeur jusqu'à ce qu'elle trouve une correspondance.
  • En tant qu'opcode, le temps système nécessaire pour appeler le in_array fonction intégrée.

Celles-ci peuvent être démontrées en utilisant un tableau avec des valeurs (10 000 dans le test ci-dessous), forçant in_array faire plus de recherches.

isset:    0.009623
in_array: 1.738441

Cela s'appuie sur le point de repère de Jason en renseignant des valeurs aléatoires et en recherchant parfois une valeur existant dans le tableau. Tous au hasard, alors méfiez-vous que les temps vont fluctuer.

$a = array();
for ($i = 0; $i < 10000; ++$i) {
    $v = Rand(1, 1000000);
    $a[$v] = $v;
}
echo "Size: ", count($a), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    isset($a[Rand(1, 1000000)]);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    in_array(Rand(1, 1000000), $a);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;
108
David Harkness

Ce qui est plus rapide: isset() vs in_array()

isset() est plus rapide.

Bien que cela soit évident, isset() ne teste qu'une seule valeur. Alors que in_array() va parcourir l'ensemble du tableau, en testant la valeur de chaque élément.

Une analyse comparative approximative est assez facile avec microtime() .

Résultats:

Total time isset():    0.002857
Total time in_array(): 0.017103

Remarque: Les résultats étaient similaires, qu'ils existaient ou non.

Code:

<?php
$a = array();
$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    isset($a['key']);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

$start = microtime( true );

for ($i = 0; $i < 10000; ++$i) {
    in_array('key', $a);
}

$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;

exit;

Ressources supplémentaires

Je vous encourage à regarder aussi:

39
Jason McCreary

L'utilisation de isset() tire parti d'une recherche plus rapide, car elle utilise une table de hachage table de hachage , ce qui évite d'avoir à effectuer des recherches sur O(n).

La clé est hachée d’abord en utilisant le fonction de hachage de djb pour déterminer le compartiment de clés hachées de la même manière dans O(1). Le compartiment est ensuite recherché de manière itérative jusqu'à ce que la clé exacte soit trouvée dans O(n).

Sauf exception collisions de hachage intentionnelles , cette approche donne de bien meilleures performances que in_array().

Notez que lorsque vous utilisez isset() comme vous l'avez montré, le passage des valeurs finales à une autre fonction nécessite l'utilisation de array_keys() pour créer un nouveau tableau. Un compromis de mémoire peut être fait en stockant les données à la fois dans les clés et les valeurs.

Mettre à jour

Pour voir comment vos décisions en matière de conception de code affectent les performances d'exécution, vous pouvez consulter le version compilée de votre script:

echo isset($arr[123])

compiled vars:  !0 = $arr
line     # *  op                           fetch      ext  return  operands
-----------------------------------------------------------------------------
   1     0  >   ZEND_ISSET_ISEMPTY_DIM_OBJ              2000000  ~0      !0, 123
         1      ECHO                                                 ~0
         2    > RETURN                                               null

echo in_array(123, $arr)

compiled vars:  !0 = $arr
line     # *  op                           fetch      ext  return  operands
-----------------------------------------------------------------------------
   1     0  >   SEND_VAL                                             123
         1      SEND_VAR                                             !0
         2      DO_FCALL                                 2  $0      'in_array'
         3      ECHO                                                 $0
         4    > RETURN                                               null

Non seulement in_array() utilise une recherche relativement inefficace O(n), elle doit également être appelée en tant que fonction (DO_FCALL) Alors que isset() utilise un opcode unique (ZEND_ISSET_ISEMPTY_DIM_OBJ) pour cela.

18
Ja͢ck

La seconde serait plus rapide, car elle ne cherche que cette clé de tableau spécifique et n'a pas besoin de parcourir l'ensemble du tableau tant qu'elle n'a pas été trouvée (examinera chaque élément de tableau s'il n'est pas trouvé).

7
Mike Brant