Arrays mit von PHP zur verfügung gestellten Funktionen sortieren
Sie befinden sich:
Home >
Php >
Arrays mit von PHP zur verfügung gestellten Funktionen sortieren
Um Arrays sortieren zu können bietet PHP einige sehr komfortable Funktionen
an. Da diese Funktionen praktisch selbsterklärend sind folgen ein paar Beispiele
mit den dazugehörigen Ausgaben.
<?php
$array = $array2 = array("bild12.gif", "bild10.gif",
"bild2.gif", "bild1.gif");
sort($array);
echo "<i>Ausgabe von \$array, Standard mit sort()</i><br>";
echo '<pre>',print_r($array,true),'</pre>';
natsort($array2);
echo "<br><i>Beispiel von \$array2, natürlich
mit natsort()</i><br>";
echo '<pre>',print_r($array2,true),'</pre>';
?>
Dieses Programm liefert folgende Ausgabe :
Ausgabe von $array, Standard mit sort() Array
(
[0] => bild1.gif
[1] => bild10.gif
[2] => bild12.gif
[3] => bild2.gif
)
Beispiel von $array2, natürlich mit natsort() Array
(
[3] => bild1.gif
[2] => bild2.gif
[1] => bild10.gif
[0] => bild12.gif
)
Es ist einfach zu erkennen das die natürliche Sortierung einer im Alltag
üblichen gleicht. Betriebsysteme sortieren gelegentlich Dateien nach der
Standardmethode so das es Anfängern oft schwer füllt Dateien zu finden.
Um Arrays sortieren zu können die über Feldindizes verfügen findet die
Funktion sort() anwendung. Im nachfolgenden Beispiel verwende ich eine
foreach Schleife um
das Array auszugeben.
Beispiel mit sort():
Sortierung von kleiner nach größer auf den Feldinhalten bezogen und
Schlüsselassoziationen werden nicht beibehalten.
<?php
$text = array("Ich", "bin", "ein", "testtext");
sort($text);
foreach ($text as $key => $val) {
echo "text[" . $key . "] = " . $val.'<br>';
}
?>
Das sortierte Array würde wie folgt ausgegeben.
Ausgabe mit sort():
text[0] = Ich text[1] = bin text[2] = ein text[3] = testtext
Um in umgekehrter Reihenfolge (absteigend) zu sortieren, wird die PHP Funktion rsort() verwendet.
Beispiel für rsort():
Sortierung von größer nach kleiner auf den Feldinhalten bezogen und
Schlüsselassoziationen werden nicht beibehalten.
<?php
$text = array("Ich", "bin", "ein", "testtext");
rsort($text);
foreach ($text as $key => $val) {
echo "text[" . $key . "] = " . $val.'<br>';
}
?>
Für das rsort() Beispiel sähe die Ausgabe dann so aus.
Die Ausgabe mit rsort():
text[0] = testtext text[1] = ein text[2] = bin text[3] = Ich
Da PHP die Möglichkeit bietet assoziative Feldindizes zu verwenden gibt es
eine spezielle Funktion ( inclusive einer umgekehrt sortierenden Funktion ) um diese zu
sortieren.
Beispiel mit ksort():
Array sortiert von kleiner nach größer auf die Feldindizes bezogen und
Schlüsselassoziationen werden beibehalten.
<?php
$text = array("d"=>"Ich", "a"=>"bin",
"c"=>"ein", "b"=>"testtext");
ksort($text);
foreach ($text as $key => $val) {
echo "text[" . $key . "] = " . $val.'<br>';
}
?>
Sortiert ausgegeben mit ksort():
text[a] = bin text[b] = testtext text[c] = ein text[d] = Ich
Beispiel mit krsort():
Array sortiert von größer nach kleiner auf die Feldindizes bezogen und
Schlüsselassoziationen werden beibehalten.
<?php
$text = array("d"=>"Ich", "a"=>"bin",
"c"=>"ein", "b"=>"testtext");
krsort($text);
foreach ($text as $key => $val) {
echo "text[" . $key . "] = " . $val.'<br>';
}
?>
Umgekehrt sortierte Ausgabe mit krsort():
text[d] = Ich text[c] = ein text[b] = testtext text[a] = bin
Grade bei Verwendung von assoziativen Arrays kommt es häufiger vor das nicht
nach Indizes sortiert werden soll, sondern nach den Feldinhalten selber. Um dies
zu erreichen verwendet man asort() oder umgekehrt sortierend arsort()
Beispiel mit asort():
Sortierung von kleiner nach größer auf den Feldinhalten bezogen und
Schlüsselassoziationen werden beibehalten.
<?php
$text = array("d"=>"Ich", "a"=>"bin",
"c"=>"ein", "b"=>"testtext");
asort($text);
foreach ($text as $key => $val) {
echo "text[" . $key . "] = " . $val.'<br>';
}
?>
Sortiert ausgegeben mit asort():
text[d] = Ich text[a] = bin text[c] = ein text[b] = testtext
Beispiel mit arsort():
Sortierung von größer nach kleiner auf den Feldinhalten bezogen und
Schlüsselassoziationen werden beibehalten.
<?php
$text = array("d"=>"Ich", "a"=>"bin",
"c"=>"ein", "b"=>"testtext");
arsort($text);
foreach ($text as $key => $val) {
echo "text[" . $key . "] = " . $val.'<br>';
}
?>
Umgekehrt sortierte Ausgabe mit arsort():
text[b] = testtext text[c] = ein text[a] = bin text[d] = Ich
Eine Beschreibung der Funktionen uksort() und uasort(), die ebenfalls von
PHP bereit gestellt werden, bei denen man eigene Algorithmen angeben kann nach
denen die Arrays sortiert werden sollen, würden den Rahmen dieser Abhandlung
sprengen, zumal hierfür Vergleichsfunktionen geschrieben werden
müssten.
Man kann ein Array auch über einen so genannten Bubblesort
sortieren.
Dieser verbraucht aber Ressourcen und man sollte lieber die von PHP zur Verfügung gestellten
Funktionen verwenden. Wenn Sie noch weitere Fragen zu
der Sortierung von einen Array haben, so können Sie sichekt in unserem Forum Ihre Frage stellen.
Auf der nachfolgenden Seite wird Ihnen erklärt, wie Sie ein mehrdimensionales
Array sortieren können. Es wird hierzu die PHP Function array_multisort() verwendet.
Die Sortierfunktionen von PHP im Ueberblick
PHP bringt eine ganze Familie von Sortierfunktionen mit, und auf den ersten Blick sehen viele davon austauschbar aus. Sie unterscheiden sich aber in drei wichtigen Punkten: ob sie nach Wert oder Schlüssel sortieren, ob sie die Schlüssel-Wert-Beziehung erhalten und in welcher Richtung sie arbeiten. Wenn Sie diese drei Achsen einmal verinnerlicht hast, wissen Sie bei jedem Problem sofort, zu welcher Funktion Sie greifen müssen. Es lohnt sich also, einen Moment Zeit in eine kleine Uebersichtstabelle zu investieren, bevor Sie im Code blind eine Funktion auswählen.
| Funktion | Sortiert nach | Richtung | Schlüssel erhalten |
sort() | Wert | aufsteigend | nein (neu durchnummeriert) |
rsort() | Wert | absteigend | nein |
asort() | Wert | aufsteigend | ja |
arsort() | Wert | absteigend | ja |
ksort() | Schlüssel | aufsteigend | ja |
krsort() | Schlüssel | absteigend | ja |
usort() | Callback | frei | nein |
uasort() | Callback | frei | ja |
uksort() | Callback (Schlüssel) | frei | ja |
natsort() | Wert (natürlich) | aufsteigend | ja |
natcasesort() | Wert (case-insensitive) | aufsteigend | ja |
Die Eselsbruecke ist einfach. Ein vorangestelltes a steht für "associative", die Schlüssel bleiben also intakt. Ein k sortiert nach den Keys statt nach den Werten. Ein r dreht die Richtung um, und ein u übergibt die Entscheidung an Ihre eigene Callback-Funktion. Sobald sich diese vier Buchstaben in Fleisch und Blut uebergegangen sind, müssen Sie die Tabelle nicht mehr nachschlagen.
Stable Sort seit PHP 8.0
Ein Detail, das vor PHP 8.0 viele Entwicklerinnen und Entwickler in den Wahnsinn getrieben hat, ist die Stabilitaet des Sortier-Algorithmus. Eine Sortierung gilt als stabil, wenn zwei Elemente mit gleichem Sortierwert nach dem Sortieren noch in der gleichen Reihenfolge stehen wie davor. Bis PHP 7.4 war das nicht garantiert. Seit PHP 8.0 sind alle eingebauten Sortierfunktionen stabil, was Ihren Code auf einen Schlag deutlich vorhersehbarer macht.
<?php
declare(strict_types=1);
$leute = [
['name' => 'Anna', 'team' => 'A'],
['name' => 'Bernd', 'team' => 'B'],
['name' => 'Clara', 'team' => 'A'],
['name' => 'Dirk', 'team' => 'B'],
];
/* Sortieren nach Team. Innerhalb eines Teams bleibt die
Original-Reihenfolge erhalten, weil PHP 8 stabil sortiert. */
usort($leute, fn($a, $b) => $a['team'] <=> $b['team']);
foreach ($leute as $l) {
echo $l['team'] . ': ' . $l['name'] . "
";
}
/* A: Anna
A: Clara
B: Bernd
B: Dirk */
Was bedeutet das konkret für sich? Sie können jetzt mehrstufig sortieren, indem Sie erst nach dem zweitwichtigsten Kriterium und dann nach dem wichtigsten sortieren. Vor PHP 8 war das ein Glücksspiel und brauchte Tricks wie eine zusammengesetzene Vergleichsfunktion. Heute reicht oft ein zweimaliges usort, und Sie bekommen genau das Ergebnis, das Sie erwartest.
Spaceship-Operator: das Schweizer Taschenmesser für usort
Wenn Sie eigene Sortierlogik mit usort umsetzen, führt kein Weg am Drei-Wege-Vergleichsoperator vorbei. Der Spaceship-Operator <=> liefert genau das, was eine Vergleichsfunktion braucht: -1, 0 oder 1. Damit ist Schluss mit umstaendlichen if-Anweisungen und manuellen Subtraktionen. Eine Zeile reicht für den Standardfall.
<?php
declare(strict_types=1);
$zahlen = [42, 7, 100, 23, 1];
/* Aufsteigend sortieren mit Spaceship-Operator. */
usort($zahlen, fn(int $a, int $b): int => $a <=> $b);
print_r($zahlen);
/* Array ( [0] => 1 [1] => 7 [2] => 23 [3] => 42 [4] => 100 ) */
/* Absteigend? Einfach die Operanden tauschen. */
usort($zahlen, fn(int $a, int $b): int => $b <=> $a);
Der große Vorteil gegenueber der alten Subtraktionsschreibweise $a - $b ist die Sicherheit. Bei sehr großen Zahlen oder Floats konnte die Subtraktion Ueberlaeufe und Genauigkeitsfehler produzieren. Der Spaceship-Operator umgeht das komplett, weil PHP intern mit den richtigen Vergleichsregeln arbeitet. Auch für Strings, Datumswerte und Arrays liefert <=> sinnvolle Ergebnisse.
Objekte nach Property sortieren
Sobald Ihre Daten in Objekte gewandert sind, brauchen Sie eine Vergleichsfunktion, die in das Objekt hineinschaut. Genau dafuer ist usort da. Sie greifst auf die gewuenschte Property zu und geben das Ergebnis des Spaceship-Vergleichs zurueck. Mit kurzen Pfeilfunktionen wird das richtig elegant.
<?php
declare(strict_types=1);
class Produkt
{
public function __construct(
public readonly string $name,
public readonly float $preis,
) {}
}
$katalog = [
new Produkt('Tastatur', 79.90),
new Produkt('Maus', 19.50),
new Produkt('Monitor', 299.00),
new Produkt('Webcam', 59.00),
];
/* Sortieren nach Preis aufsteigend. */
usort($katalog, fn(Produkt $a, Produkt $b): int => $a->preis <=> $b->preis);
foreach ($katalog as $p) {
echo $p->name . ': ' . number_format($p->preis, 2, ',', '.') . " €
";
}
Der gleiche Trick funktioniert mit jeder oeffentlichen Property und mit Methoden, die einen vergleichbaren Wert zurueckgeben. Ein $a->getCreatedAt() <=> $b->getCreatedAt() ist genauso erlaubt. Achten Sie nur darauf, dass die Methode pure ist und keine Seiteneffekte hat, denn sie wird während des Sortierens sehr oft aufgerufen.
Multi-Key-Sortierung: erst Spalte A, dann Spalte B
In der echten Welt wollen Sie selten nur nach einem Kriterium sortieren. Eine Liste von Mitarbeitenden soll zum Beispiel zuerst nach Abteilung und innerhalb jeder Abteilung nach Nachname sortiert werden. Mit dem Spaceship-Operator und dem Null-Coalescing-Operator ?? wird daraus ein lesbarer Einzeiler.
<?php
declare(strict_types=1);
$mitarbeitende = [
['abteilung' => 'IT', 'nachname' => 'Schmidt'],
['abteilung' => 'HR', 'nachname' => 'Mueller'],
['abteilung' => 'IT', 'nachname' => 'Becker'],
['abteilung' => 'HR', 'nachname' => 'Anders'],
['abteilung' => 'Sales', 'nachname' => 'Krause'],
];
usort($mitarbeitende, function (array $a, array $b): int {
return ($a['abteilung'] <=> $b['abteilung'])
?: ($a['nachname'] <=> $b['nachname']);
});
foreach ($mitarbeitende as $m) {
echo $m['abteilung'] . ' / ' . $m['nachname'] . "
";
}
Das Muster $primaer ?: $sekundaer nutzen die Tatsache aus, dass der Spaceship-Operator bei Gleichheit eine Null liefert. Eine Null ist falsy, also greift der zweite Operand. Genauso können Sie auch ein drittes oder viertes Sortierkriterium dranhaengen.
Parallele Sortierung mit array_multisort
Manchmal haben Sie nicht eine Liste von Datensaetzen, sondern mehrere parallele Arrays, die zusammen einen Datensatz bilden. Klassischer Fall: Eine Spalte mit Namen, eine mit Punkten, beide gleich lang. Wenn Sie jetzt nach den Punkten sortieren, soll die Reihenfolge der Namen mitwandern. Genau dafuer ist array_multisort gemacht.
<?php
declare(strict_types=1);
$namen = ['Anna', 'Bernd', 'Clara', 'Dirk'];
$punkte = [78, 92, 65, 88];
/* Sortiere nach Punkten absteigend, Namen wandern mit. */
array_multisort($punkte, SORT_DESC, SORT_NUMERIC, $namen);
foreach ($namen as $i => $name) {
echo $name . ': ' . $punkte[$i] . " Punkte
";
}
Sie können auch mehrere Sortierachsen kombinieren, indem Sie jeweils das nächste Array, gefolgt von einem Richtungs-Flag, an array_multisort übergeben. Die Reihenfolge entscheidet über die Prioritaet. Erst wird nach dem ersten Array sortiert, bei Gleichstand nach dem zweiten und so weiter. In der Praxis ist usort mit dem Multi-Key-Pattern aus dem vorherigen Abschnitt aber meistens lesbarer, weil dort der Bezug zwischen den Feldern eines Datensatzes klarer bleibt.
Locale-aware sortieren mit dem Collator
Sobald deutsche Umlaute, franzoesische Akzente oder spanische Sonderzeichen ins Spiel kommen, stoesst die Standard-Sortierung an ihre Grenzen. sort arbeitet byte-weise und sortiert Ä dann irgendwo hinter Z. Für korrekte sprachabhaengige Reihenfolgen brauchen Sie die Collator-Klasse aus der intl-Erweiterung.
<?php
declare(strict_types=1);
$staedte = ['Zwickau', 'Ängelholm', 'Augsburg', 'Oerlinghausen', 'Aachen'];
$collator = new Collator('de_DE');
$collator->sort($staedte);
print_r($staedte);
/* Aachen, Aengelholm, Augsburg, Oerlinghausen, Zwickau */
Achten Sie darauf, dass die intl-Erweiterung auf Ihrem Server installiert ist. Auf den meisten modernen Hostings ist sie Standard, auf manchen Shared-Hosting-Paketen aber leider nicht. Pruefen können Sie das schnell mit extension_loaded('intl').
Welche Funktion für welchen Fall?
Wenn Sie jetzt vor einem konkreten Problem stehst, hilft sich vielleicht ein kleiner Entscheidungsbaum. Er fragt sich genau die drei Achsen ab, die wir am Anfang besprochen haben, und führt sich zur passenden Funktion.
flowchart TD
A[Was sortieren?] --> B{Eigene Logik?}
B -->|Ja| C[usort/uasort/uksort]
B -->|Nein| D{Schluessel oder Wert?}
D -->|Schluessel| E[ksort/krsort]
D -->|Wert| F{Schluessel erhalten?}
F -->|Ja| G[asort/arsort]
F -->|Nein| H[sort/rsort]
Drei Fragen, fünf Endpunkte, und in 90 Prozent der Faelle haben Sie genau die richtige Funktion.
Praxisbeispiel: User-Liste nach Alter und Name
Zum Abschluss bringen wir alles zusammen. Stell sich eine User-Tabelle vor, die Sie in einem Backend ausgeben. Die Anforderung: zuerst die jüngsten zuerst, und bei gleichem Alter alphabetisch nach Vorname.
<?php
declare(strict_types=1);
final class User
{
public function __construct(
public readonly string $vorname,
public readonly int $alter,
) {}
}
$users = [
new User('Tarek', 34),
new User('Anna', 28),
new User('Bernd', 28),
new User('Clara', 41),
new User('Dirk', 28),
];
/* Erst nach Alter, dann nach Vorname (alphabetisch). */
$collator = new Collator('de_DE');
usort($users, function (User $a, User $b) use ($collator): int {
return ($a->alter <=> $b->alter)
?: $collator->compare($a->vorname, $b->vorname);
});
foreach ($users as $u) {
printf("%2d Jahre - %s
", $u->alter, $u->vorname);
}
Was hier alles drinsteckt: typsichere Klassen mit Constructor-Promotion, eine kombinierte Sortierung mit ?:, ein Collator für korrekte Umlaut-Behandlung und das stabile Sortierverhalten von PHP 8. Wenn die Daten aus einer Datenbank kommen, würden Sie die Sortierung natürlich besser über ORDER BY ans DBMS auslagern. Sobald Sie aber im PHP-Speicher arbeiten, etwa mit gefilterten Sammlungen, Service-Antworten oder Cached-Daten, ist genau dieses Muster Ihr Werkzeug der Wahl.
weiter zum nächsten Kapitel:
if Anweisung in PHP
|