Hallo dedlfix,
an der Vergleichsfunktion ist einiges im Argen. Und nicht nur da.
- die Schleife für den Aufbau von $newArr ist sehr merkwürdig gebaut.
- unnötiges Swapping, wie schon von Dir genannt
- unnötiges unset einer lokalen Variablen, die verdampft am Funktionsende sowieso
- unnötig aufwändiger Vergleich im numeric Zweig
function myCompare($a, $b, $invers = false ) {
$inv = $invers ? -1 : 1;
if ( is_string( $a ) and is_string( $b ) ) {
return strcmp( $a, $b ) * $inv;
} elseif ( is_numeric( $a ) and is_numeric( $b ) ) {
if ( $a == $b ) return 0;
if ( $a < $b ) return -$inv;
return $inv;
// oder: return ($a == $b) ? 0 : (($a < $b) ? -$inv : $inv);
// oder (PHP 7): return ($a <=> $b) * $inv;
}
trigger_error( 'Nicht unterstützter Vergleich von '.gettype($a).' und '.gettype($b).' in Funktion myCompare. Erlaubt sind string und numeric', E_USER_ERROR );
}
Generell würde ich aber einen Sortier-Callback nicht unnötig mit Helpern und Abstraktion belasten. Wenn's irgendwo schnell gehen muss, dann dort. Das bedeutet: Typen prüft man vor dem Sortieren und nicht im Callback, denn ein Sortieralgorithmus packt die Einträge im Array mehrfach an. Was auch lohnt, ist die Frage nach der PHP Version: Ist es 7 oder mehr? Denn dann haben wir den Spaceship-Operator, der zum Sortieren sehr nützlich ist.
function compare_Datum_UID_Prio_Prio2 ( $a, $b ) {
$result = $a['Datum'] <=> $b['Datum'];
if ($result != 0) return $result;
$result = $a['UID'] <=> $b['UID'];
if ($result != 0) return $result;
$result = $b['Prio'] <=> $a['Prio']; // invers!
if ($result != 0) return $result;
return $b['Prio2'] <=> $a['Prio2']; // invers!
}
Diesen Code könnte man noch weiter eindampfen, aber dann wird er schwer lesbar.
Ohne Spaceship könnte man über einen Compare-Helper nachdenken, oder es doch stumpf runterprogrammieren. Funktionsaufrufe sind vor PHP 7 deutlich langsamer gewesen.
function compare_Datum_UID_Prio_Prio2 ( $a, $b ) {
if ($a['Datum'] < $b['Datum']) return -1;
if ($a['Datum'] > $b['Datum']) return 1;
if ($a['UID'] < $b['UID']) return -1;
if ($a['UID'] > $b['UID']) return 1;
if ($a['Prio'] < $b['Prio']) return 1; // Invers!
if ($a['Prio'] > $b['Prio']) return -1;
if ($a['Prio2'] < $b['Prio2']) return 1; // Invers!
if ($a['Prio2'] > $b['Prio2']) return -1;
return 0;
}
Nochmal zurück zum ersten Punkt: die Schleife für den Aufbau von $newArr ist sehr merkwürdig gebaut.
- Ein unset auf das foreach-Item funktioniert nicht (und ist mutmaßlich auch unnötig), wegen des copy-on-write Verhaltens von PHP. Man müsste schon über eine Referenz iterieren:
foreach ($arr as &$item)
. Dann wirken sich die unset in $arr aus. $newArr[ $uid ] = [];
ist unnötig, wie beim Erstellen des Testdaten-Arrays $arr gezeigt wird. PHP legt bei$newArr[ $uid ][] = $item;
automatisch einen Array-Eintrag an.
Rolf
sumpsi - posui - obstruxi