Da es nicht so aussieht, als hätte das schon jemand gemacht, dachte ich, es wäre eine gute Idee, es irgendwo als Referenz zu haben. Ich bin durchgegangen und habe entweder mittels Benchmark oder Code-Skimming die array_*
Funktionen. Ich habe versucht, die interessanteren Big-O an die Spitze zu stellen. Diese Liste ist nicht vollständig.
Hinweis: Alle Big-O wurden unter der Annahme berechnet, dass ein Hash-Lookup O(1) ist, obwohl es in Wirklichkeit O(n) ist. Der Koeffizient von n ist so niedrig, dass der Aufwand für die Speicherung eines ausreichend großen Arrays Sie schmerzen würde, bevor die Eigenschaften des Big-O-Lookups zum Tragen kommen. Zum Beispiel ist der Unterschied zwischen einem Aufruf von array_key_exists
bei N=1 und N=1.000.000 ist ~50% Zeitgewinn.
Interessante Punkte :
isset
/ array_key_exists
ist viel schneller als in_array
y array_search
+
(Vereinigung) ist ein wenig schneller als array_merge
(und sieht schöner aus). Aber es funktioniert anders, also bedenken Sie das.
shuffle
ist auf der gleichen Big-O-Ebene wie array_rand
array_pop
/ array_push
ist schneller als array_shift
/ array_unshift
wegen der Re-Indexierungsstrafe
Nachschlagen :
array_key_exists
O(n), aber wirklich nahe an O(1) - das liegt an der linearen Abfrage bei Kollisionen, aber da die Wahrscheinlichkeit von Kollisionen sehr gering ist, ist auch der Koeffizient sehr klein. Ich finde, man behandelt Hash-Lookups als O(1), um ein realistischeres Big-O zu erhalten. Zum Beispiel ist der Unterschied zwischen N=1000 und N=100000 nur etwa 50% langsamer.
isset( $array[$index] )
O(n), aber wirklich nahe an O(1) - es verwendet den gleichen Lookup wie array_key_exists. Da es sich um ein Sprachkonstrukt handelt, wird die Suche gecacht, wenn der Schlüssel hartkodiert ist, was zu einer Beschleunigung in Fällen führt, in denen derselbe Schlüssel wiederholt verwendet wird.
in_array
O(n) - das liegt daran, dass eine lineare Suche durch das Array durchgeführt wird, bis der Wert gefunden ist.
array_search
O(n) - verwendet die gleiche Kernfunktion wie in_array, gibt aber einen Wert zurück.
Warteschlangenfunktionen :
array_push
O( var_i, für alle i)
array_pop
O(1)
array_shift
O(n) - es müssen alle Schlüssel neu indiziert werden
array_unshift
O(n + var_i, für alle i) - es müssen alle Schlüssel neu indiziert werden
Array-Schnittmenge, Vereinigung, Subtraktion :
array_intersect_key
wenn Schnittmenge 100% O(Max(param_i_size)*param_i_count, für alle i), wenn Schnittmenge 0% Schnittmenge O(param_i_size, für alle i)
array_intersect
wenn Schnittmenge 100% O(n^2*param_i_count, für alle i), wenn Schnittmenge 0% Schnittmenge O(n^2)
array_intersect_assoc
wenn Schnittmenge 100% O(Max(param_i_size)*param_i_count, für alle i), wenn Schnittmenge 0% Schnittmenge O(param_i_size, für alle i)
array_diff
O( param_i_size, für alle i) - Das ist das Produkt aus allen param_sizes
array_diff_key
O( param_i_size, for i != 1) - das liegt daran, dass wir nicht über das erste Array iterieren müssen.
array_merge
O( array_i, i != 1 ) - braucht nicht über das erste Array zu iterieren
+
(union) O(n), wobei n die Größe des 2. Arrays ist (d.h. array_first + array_second) - weniger Overhead als array_merge, da es nicht neu nummerieren muss
array_replace
O( array_i, für alle i )
Zufällig :
shuffle
O(n)
array_rand
O(n) - Erfordert eine lineare Abfrage.
Offensichtlich Big-O :
array_fill
O(n)
array_fill_keys
O(n)
range
O(n)
array_splice
O(Versatz + Länge)
array_slice
O(Offset + Länge) oder O(n) wenn Länge = NULL
array_keys
O(n)
array_values
O(n)
array_reverse
O(n)
array_pad
O(pad_size)
array_flip
O(n)
array_sum
O(n)
array_product
O(n)
array_reduce
O(n)
array_filter
O(n)
array_map
O(n)
array_chunk
O(n)
array_combine
O(n)
Ich möchte mich bedanken bei Eureqa dafür, dass es einfach ist, das Big-O der Funktionen zu finden. Es ist eine erstaunliche kostenlos Programm, das die beste Anpassungsfunktion für beliebige Daten finden kann.
EDITAR:
Für diejenigen, die bezweifeln, dass PHP Array Lookups sind O(N)
Ich habe einen Benchmark geschrieben, um das zu testen (sie sind immer noch effektiv O(1)
für die meisten realistischen Werte).
![php array lookup graph]()
$tests = 1000000;
$max = 5000001;
for( $i = 1; $i <= $max; $i += 10000 ) {
//create lookup array
$array = array_fill( 0, $i, NULL );
//build test indexes
$test_indexes = array();
for( $j = 0; $j < $tests; $j++ ) {
$test_indexes[] = rand( 0, $i-1 );
}
//benchmark array lookups
$start = microtime( TRUE );
foreach( $test_indexes as $test_index ) {
$value = $array[ $test_index ];
unset( $value );
}
$stop = microtime( TRUE );
unset( $array, $test_indexes, $test_index );
printf( "%d,%1.15f\n", $i, $stop - $start ); //time per 1mil lookups
unset( $stop, $start );
}
32 Stimmen
Völlig abseits des Themas, aber 1 ist nicht primär.
25 Stimmen
Arrays in PHP sind Hashtabellen. Das sollte Ihnen alles sagen, was Sie wissen müssen. Die Suche nach einem Schlüssel in einer Hashtabelle ist O(1). Die Suche nach einem Wert ist O(n) - was bei einer unsortierten Menge nicht zu schlagen ist. Die meisten Funktionen, auf die Sie neugierig sind, sind wahrscheinlich O(n). Wenn Sie es wirklich wissen wollen, können Sie natürlich den Quelltext lesen: cvs.php.net/viewvc.cgi/php-src/ext/standard/
12 Stimmen
Für das Protokoll, die schnellste Implementierung von dem, was Sie versuchen zu tun, wäre (anstelle der Verwendung von NULL für Ihre Werte) zu verwenden
true
und testen Sie dann das Vorhandensein mitisset($large_prime_array[$number])
. Wenn ich mich richtig erinnere, ist sie hundertmal schneller als diein_array
Funktion.1 Stimmen
Mattbasta; wenn das, was du sagst, wahr ist, dann habe ich gerade das Coolste gelernt, was ich die ganze Woche gelernt habe.
0 Stimmen
@mattbasta hätte es dann nicht immer noch dasselbe große O, nur mit einem kleineren Koeffizienten?
0 Stimmen
@Kendall Bin mir nicht ganz sicher, aber ich habe es benutzt und es ist Wahnsinnig schnell.
0 Stimmen
@mattbasta Nach meinen Tests ist der einzige Grund, dass isset schneller ist, weil es ein Sprachkonstrukt ist, und es gibt ein bisschen Überkopf für array_key_exists. Dieser Overhead laut meinem Test pastebin.com/E9WtuzPb ist nur ~50 % (Unterschied zwischen 0,0000006 und 0,0000004). Ich glaube, der Grund, warum isset um Größenordnungen schneller sein kann, ist, dass es Lookups zwischenspeichern kann, wenn der Schlüssel hardcodiert ist, weil es ein Sprachkonstrukt ist. Ich denke, ich werde immer noch mit array_key_exists bleiben, weil es nicht die NULL gotcha hat.
3 Stimmen
Bei der Big-O-Notation geht es nicht um Geschwindigkeit. Es geht darum, das Verhalten einzuschränken.
3 Stimmen
@Kendall Ich vergleiche nicht mit
array_key_exists
vergleiche ich mitin_array
.in_array
durchläuft jedes Element im Array und vergleicht den Wert mit der Nadel, die Sie ihm übergeben. Wenn Sie die Werte mit dem Schlüssel spiegeln (und einfach jeden der Werte durch einen Dummy-Wert ersetzen wietrue
, mitisset
ist um ein Vielfaches schneller. Das liegt daran, dass die Schlüssel eines Arrays von PHP indiziert werden (wie eine Hashtabelle). Folglich kann die Suche in einem Array auf diese Weise eine erhebliche Geschwindigkeitssteigerung bewirken.0 Stimmen
Interessant! Eine schnelle Umstellung, um die 2., schnellere Form zu verwenden, ist $prime_array = array_fill_keys( $prime_array, null ) . Dadurch werden die Schlüssel in Werte umgewandelt und wir können isset() anstelle von in_array() verwenden. Von stackoverflow.com/questions/10641865/
0 Stimmen
$array_of_number ist nicht definiert ??