Domanda

È più veloce eseguire le seguenti operazioni:

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

o

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

Esiste un numero di valori a quel punto è più veloce fare l'uno o l'altro?

(In questo caso, l'array utilizzato nella seconda opzione non esiste alreay.)

È stato utile?

Soluzione

Suggerirei vivamente di usare in_array () , qualsiasi differenza di velocità sarebbe trascurabile, ma la leggibilità di testare ciascuna variabile separatamente è orribile.

solo per divertimento ecco un test che ho eseguito:

$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 un po 'banale da tenere d'occhio, se $ var non è impostato, il metodo 1 impiega molto più tempo (a seconda di quante condizioni testerai)

Altri suggerimenti

Nota che se stai cercando di sostituire un mucchio di istruzioni ! == , dovresti passare il terzo parametro a in_array come true , che impone il controllo del tipo sugli elementi dell'array.

L'ordinario ! = non lo richiede, ovviamente.

Il primo sarà più veloce - il secondo ha un sacco di sovraccarico: creazione dell'array, chiamata di una funzione, ricerca dell'array ...

Tuttavia, come ho detto in una domanda un paio di risposte, l'ottimizzazione prematura è la radice di tutti i mali. Dovresti scrivere il tuo codice per essere leggibile, quindi se deve essere ottimizzato, quindi ottimizzalo.

Modifica:

I miei tempi con il codice di @ Owen (PHP 5.2.6 / windows):

Time1: 1.33601498604
Time2: 4.9349629879

Spostamento dell'array (...) all'interno del loop, come nella domanda:

Time1: 1.34736609459
Time2: 6.29464697838

in_array sarà più veloce per un gran numero di elementi. & Quot; grande " essendo molto soggettivo in base a molti fattori legati ai dati e al tuo computer. Dal momento che stai chiedendo, presumo che non hai a che fare con un numero banale di articoli. Per elenchi più lunghi, consulta queste informazioni , e misurare le prestazioni con un array capovolto in modo che php possa utilizzare le ricerche hash invece di una ricerca lineare. Per un "statico" array che ottimizza potrebbe non migliorare le prestazioni, ma potrebbe anche.

Utilizzo del codice di test di Owen, con un array capovolto e più iterazioni per risultati più coerenti:

$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

Ciao, ho appena portato questo caso al limite e ho sottolineato che con un numero crescente di valori il semplice confronto è non il modo più efficace.

Ecco il mio codice:

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

I miei risultati (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

Sono d'accordo, è un po 'estremo ma mostra il quadro generale e il grande potenziale negli array associativi simili a hash-table di PHP, devi solo usarlo

Si noti che, come sottolineato da RoBorg, c'è un sovraccarico nella creazione dell'array, quindi dovrebbe essere spostato all'interno del ciclo di iterazione. Per questo motivo, il post di Sparr è anche un po 'fuorviante in quanto c'è un sovraccarico con la funzione array_flip.

Ecco un altro esempio con tutte e 5 le varianti:

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

I miei risultati:

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

In breve, l'uso di array_flip (con isset) è più veloce di inarray ma non veloce come un confronto diretto.

Quando si parla di PHP e si chiede se:

  • un insieme di " if " se " else ifs " ,
  • un " if " con una serie di condizioni "o" (come nei dettagli del post originale) o
  • utilizzo di " in_array " con un array costruito al volo,

è meglio

tieni presente che il linguaggio PHP "cambia" l'affermazione è un'alternativa progettata per tali situazioni e potrebbe essere una risposta migliore. (Anche se l'esempio del poster ci porta a confrontare solo due soluzioni, l'attuale titolo della domanda chiede di considerare in_array rispetto alle dichiarazioni di PHP, quindi penso che questo sia un gioco equo).

Nell'esempio del poster, quindi, raccomanderei invece:

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

Vorrei che PHP fosse autorizzato per un paio di costrutti non primitivi nei casi, come una virgola per " o " ;. Ma quanto sopra è quello che i progettisti di PHP hanno considerato il modo più chiaro di gestirlo. E sembra essere più efficiente al momento dell'esecuzione rispetto alle altre due alternative.

Finché sto parlando di una lista dei desideri, il " IN " trovato in SQL sarebbe ancora più chiaro per la situazione di esempio del poster.

Questo pensiero è probabilmente ciò che porta le persone che vogliono usare "in_array" per tali situazioni, ma è un po 'sfortunato dover costruire una struttura di dati e quindi utilizzare un predicato progettato per quella struttura di dati, piuttosto che avere un modo per dirlo senza che si verifichi quel sovraccarico.

Ecco un aggiornamento live di questa panchina con un altro caso https://3v4l.org/OA2S7

I risultati per PHP 7.3:

  • confronti multipli: 0.0575 07991790771

  • in_array: 0.0256 8507194519

  • array_flip () loop esterno misurato + isset (): 0.0146 78001403809

  • array_flip () loop esterno non misurato + isset (): 0.0156 50033950806

  • foreach e confronto: 0.062782049179077

So che questa domanda ha quasi 10 anni, ma ci sono altri modi per farlo. Ho usato il metodo B dalla Pagina di Nick con migliaia di voci. È stato incredibilmente veloce.

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

I miei test

$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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top