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 )
Les réponses à ce jour sont parfaites. Utiliser isset
dans ce cas est plus rapide car
in_array
doit vérifier chaque valeur jusqu'à ce qu'elle trouve une correspondance.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;
Ce qui est plus rapide:
isset()
vsin_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()
.
Total time isset(): 0.002857
Total time in_array(): 0.017103
Remarque: Les résultats étaient similaires, qu'ils existaient ou non.
<?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;
Je vous encourage à regarder aussi:
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.
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é).