Ordonarea unei colecții
Sortarea înseamnă așezarea elementelor unei colecții într-o anumită ordine.
Unele tipuri au o ordine naturală. Numerele sunt ordonate după valoare: 1 vine înaintea lui 2. Șirurile de caractere sunt ordonate alfabetic: "four" vine înaintea lui "one". Pentru orice altceva, sau când vrei o altă ordine, dai o ordine personalizată: o funcție de comparare care se uită la două elemente și spune care dintre ele vine primul.
Funcțiile de sortare din PHP lucrează toate pe loc. Primesc tabloul prin referință, îl modifică și returnează true — nu tabloul sortat. $sorted = sort($words) este o greșeală clasică: $sorted devine true.
sort($s)sortează în ordine naturală, cel mai mic primul.rsort($s)sortează în ordine naturală, cel mai mare primul.usort($s, $compare)sortează cu propria ta funcție de comparare.
Toate trei renumerotează cheile cu 0, 1, 2 și așa mai departe.
Pentru a păstra ordinea originală, sortează o copie. În PHP acest lucru este simplu, deoarece tablourile sunt valori: $sorted = $words; îi dă lui $sorted propria copie, iar sortarea ei lasă $words neatins.
O funcție de comparare primește două elemente, $a și $b, și returnează un număr: negativ când $a vine primul, pozitiv când $b vine primul și 0 când sunt egale. Operatorul navă spațială <=> dă exact acest număr: $a <=> $b este -1, 0 sau 1.
Exemplele de mai jos folosesc cuvintele one, two, three, four.
Ordinea naturală
Ordinea naturală este ordinea pe care un tip o are de la sine: numerele după valoare, șirurile de caractere literă cu literă.
sort() așază un tablou în ordine naturală. Pentru ordine descrescătoare există rsort(): aceeași sortare, dar cu cel mai mare element primul. Ambele modifică tabloul pe care îl transmiți, așa că fă-i mai întâi o copie atunci când ai nevoie și de original.
Datele tale proprii, cum ar fi un număr de versiune cu o parte major și o parte minor, nu au o ordine naturală proprie. Îi dai una scriind o funcție de comparare care returnează un număr negativ, zero sau un număr pozitiv. Operatorul navă spațială compară și tablouri întregi, poziție cu poziție, iar prima diferență decide — așadar [$major, $minor] <=> [$otherMajor, $otherMinor] compară mai întâi numerele major, iar numerele minor doar atunci când cele major sunt egale.
Copie sortată
$sorted = $words; copiază tabloul, iar sort() așază copia în ordine alfabetică. Tabloul original $words este afișat după aceea, pentru a arăta că nu s-a modificat.
Ieșire: script PHP
<?php
$words = ["one", "two", "three", "four"];
// Tablourile sunt copiate la atribuire, așa că $sorted este un tablou separat.
// sort() modifică $sorted pe loc; $words rămâne așa cum a fost.
$sorted = $words;
sort($sorted);
echo implode(", ", $sorted), "\n";
echo implode(", ", $words), "\n";
Sortare descrescătoare
rsort() sortează copia cu cel mai mare primul, așa că cuvintele merg de la "two" până la "four".
Ieșire: script PHP
<?php
$words = ["one", "two", "three", "four"];
// rsort() sortează copia pe loc, cu cel mai mare primul.
$desc = $words;
rsort($desc);
echo implode(", ", $desc), "\n";
Un tip cu ordinea lui proprie
O versiune este un tablou cu un număr major și un număr minor. compareVersion() compară perechile [major, minor] cu <=>: mai întâi numerele major; doar când acestea sunt egale decid numerele minor. Verificarea compareVersion(...) > 0 răspunde la întrebarea „este prima versiune mai mare?”. json_encode() afișează valorile booleene ca false și true.
Ieșire: script PHP
<?php
declare(strict_types=1);
// compareVersion returnează un număr negativ, zero sau un număr pozitiv,
// ca funcțiile de comparare folosite de usort().
// Tablourile se compară poziție cu poziție: mai întâi major, apoi minor.
function compareVersion(array $v, array $other): int {
return [$v["major"], $v["minor"]] <=> [$other["major"], $other["minor"]];
}
$v12 = ["major" => 1, "minor" => 2];
$v13 = ["major" => 1, "minor" => 3];
$v20 = ["major" => 2, "minor" => 0];
$v15 = ["major" => 1, "minor" => 5];
// Este 1.2 mai mare decât 1.3?
echo json_encode(compareVersion($v12, $v13) > 0), "\n";
// Este 2.0 mai mare decât 1.5?
echo json_encode(compareVersion($v20, $v15) > 0), "\n";
Ordini personalizate
O ordine personalizată este orice ordine pe care o descrii cu o funcție de comparare.
usort() sortează un tablou pe loc cu această funcție. Începând cu PHP 8.0, fiecare sortare din PHP este stabilă: elementele care se compară ca fiind egale își păstrează ordinea originală. Acest lucru contează, de exemplu, la sortarea cuvintelor după lungime.
Cazul de zi cu zi este sortarea după o proprietate a fiecărui element. Pune acea proprietate de ambele părți ale operatorului navă spațială: strlen($a) <=> strlen($b) sortează după lungime.
Pentru ordine descrescătoare, inversează cele două părți: $b <=> $a în loc de $a <=> $b.
Pentru a sorta după un criteriu și apoi după altul, compară două tablouri: [strlen($a), $a] <=> [strlen($b), $b]. Lungimile se compară primele; dacă sunt egale, cuvintele în sine decid egalitatea.
Sortare cu o funcție de comparare
Funcția de comparare returnează strlen($a) <=> strlen($b). Un rezultat negativ înseamnă că $a este mai scurt și vine primul, așa că cuvintele ajung de la cel mai scurt la cel mai lung.
Ieșire: script PHP
<?php
$words = ["aaa", "bb", "c"];
// Șirurile de caractere mai scurte vin primele.
usort($words, fn($a, $b) => strlen($a) <=> strlen($b));
echo implode(", ", $words), "\n";
Sortare după lungime
Cuvintele sunt comparate după lungime. "one" și "two" au amândouă 3 litere; sortarea stabilă păstrează "one" înaintea lui "two".
Ieșire: script PHP
<?php
$words = ["one", "two", "three", "four"];
// Sortarea este stabilă: cuvintele de lungime egală își păstrează ordinea originală.
usort($words, fn($a, $b) => strlen($a) <=> strlen($b));
echo implode(", ", $words), "\n";
Sortare după ultima literă, descrescător
$a[-1] este ultima literă a unui cuvânt: un indice negativ într-un șir de caractere numără de la sfârșit. Literele lui $b și $a sunt comparate în ordine inversată, așa că vine primul cuvântul cu cea mai mare ultimă literă: "four" (r), apoi "two" (o), apoi cele două cuvinte care se termină în „e” în ordinea lor originală.
Ieșire: script PHP
<?php
$words = ["one", "two", "three", "four"];
// Compară ultimele litere, cu $b și $a inversate pentru ordine descrescătoare.
usort($words, fn($a, $b) => $b[-1] <=> $a[-1]);
echo implode(", ", $words), "\n";
Sortare după lungime, apoi alfabetic
Operatorul navă spațială compară tablourile [strlen($a), $a] și [strlen($b), $b] poziție cu poziție. Lungimile decid primele. Când două cuvinte au aceeași lungime, sunt comparate cuvintele în sine, ceea ce le ordonează alfabetic.
Ieșire: script PHP
<?php
$words = ["aaa", "bb", "c", "b", "a", "aa", "ccc"];
// Tablourile se compară poziție cu poziție: mai întâi lungimea, apoi cuvântul în sine.
usort($words, fn($a, $b) => [strlen($a), $a] <=> [strlen($b), $b]);
echo implode(", ", $words), "\n";
Verificarea ordinii de sortare
Uneori vrei doar să afli dacă un tablou este deja sortat, fără să îl sortezi.
PHP nu are o funcție încorporată pentru asta, dar o mică funcție ajutătoare este suficientă: parcurge tabloul, compară fiecare element cu vecinul său din dreapta și returnează false imediat ce o pereche este în ordine greșită. Dă funcției ajutătoare o funcție de comparare opțională și aceeași buclă verifică orice ordine. Pentru ordine descrescătoare transmite fn($a, $b) => $b <=> $a — comparația inversată.
Pentru a verifica ordinea după o singură proprietate, cum ar fi vârsta unui utilizator, compară acea proprietate în interiorul funcției.
Verificare crescătoare și descrescătoare
isSorted() confirmă că 1, 2, 3, 4 sunt în ordine crescătoare. Cu funcția de comparare $b <=> $a confirmă că 4, 3, 2, 1 sunt în ordine descrescătoare.
Ieșire: script PHP
<?php
// isSorted verifică fiecare element față de vecinul său din dreapta.
function isSorted(array $items, ?callable $compare = null): bool {
$compare ??= fn($a, $b) => $a <=> $b;
for ($i = 0; $i + 1 < count($items); $i++) {
if ($compare($items[$i], $items[$i + 1]) > 0) {
return false;
}
}
return true;
}
$ascending = [1, 2, 3, 4];
$descending = [4, 3, 2, 1];
echo json_encode(isSorted($ascending)), "\n";
// Operanzii inversați verifică ordinea descrescătoare.
echo json_encode(isSorted($descending, fn($a, $b) => $b <=> $a)), "\n";
Verificarea ordinii după un câmp
Utilizatorii sunt Alice (24), Bob (31) și Charlie (29). Funcția de comparare se uită doar la 'age'. Bob este mai în vârstă decât Charlie, așa că tabloul nu este sortat după vârstă și programul afișează false.
Ieșire: script PHP
<?php
// isSortedBy verifică fiecare pereche de vecini cu funcția de comparare.
function isSortedBy(array $items, callable $compare): bool {
for ($i = 0; $i + 1 < count($items); $i++) {
if ($compare($items[$i], $items[$i + 1]) > 0) {
return false;
}
}
return true;
}
$users = [
["name" => "Alice", "age" => 24],
["name" => "Bob", "age" => 31],
["name" => "Charlie", "age" => 29],
];
// Sunt utilizatorii în ordinea vârstei?
echo json_encode(isSortedBy($users, fn($a, $b) => $a["age"] <=> $b["age"])), "\n";
Ordinea inversă
Inversarea pune ultimul element primul și primul element ultimul.
Spre deosebire de funcțiile de sortare, array_reverse() nu modifică tabloul pe care i-l dai: returnează o copie inversată, iar originalul își păstrează ordinea.
Copie inversată
Copia creată de array_reverse() este afișată, apoi este afișat originalul pentru a arăta că este neschimbat.
Ieșire: script PHP
<?php
$words = ["one", "two", "three", "four"];
// array_reverse() returnează o copie inversată; originalul își păstrează ordinea.
$reversed = array_reverse($words);
echo implode(", ", $reversed), "\n";
echo implode(", ", $words), "\n";
Ordine aleatoare
Amestecarea așază elementele într-o ordine aleatoare.
shuffle() din PHP funcționează ca funcțiile de sortare: pe loc, asupra tabloului pe care îl transmiți. Amestecă o copie dacă ai nevoie și de original.
shuffle() își ia numerele aleatoare din același generator ca mt_rand(). Inițializează acel generator cu mt_srand(seed) și obții aceeași ordine „aleatoare” la fiecare rulare a programului cu acea sămânță. Acest lucru este util pentru teste și pentru exemple ca acesta. Fără o sămânță fixă, ordinea se schimbă la fiecare rulare.
Copie amestecată
mt_srand(14) fixează sămânța, apoi shuffle() amestecă o copie a cuvintelor. Parcurge de la ultima poziție la prima și schimbă fiecare element cu unul ales aleatoriu pe poziția lui sau înaintea ei. Cu această sămânță, rezultatul este two, three, one, four la fiecare rulare.
Ieșire: script PHP
<?php
$words = ["one", "two", "three", "four"];
// O sămânță fixă dă aceeași ordine „aleatoare” la fiecare rulare.
mt_srand(14);
// shuffle() lucrează pe loc, așa că amestecă o copie.
$shuffled = $words;
shuffle($shuffled);
echo implode(", ", $shuffled), "\n";