Wie kann ich Arrays und Daten in PHP sortieren?

292

Diese Frage ist als Referenz für Fragen zum Sortieren von Arrays in PHP gedacht. Es ist leicht zu glauben, dass Ihr spezieller Fall einzigartig ist und eine neue Frage verdient, aber die meisten sind tatsächlich geringfügige Variationen einer der Lösungen auf dieser Seite.

Wenn Ihre Frage als Duplikat dieser Frage geschlossen ist, bitten Sie darum, dass Ihre Frage nur dann wieder geöffnet wird, wenn Sie erklären können, warum sie sich deutlich von allen folgenden unterscheidet.

Wie sortiere ich ein Array in PHP?
Wie sortiere ich ein komplexes Array in PHP?
Wie sortiere ich ein Array von Objekten in PHP?


  1. Grundlegende eindimensionale Arrays; Inkl. Mehrdimensionale Arrays, inkl. Anordnungen von Objekten; Inkl. Sortieren eines Arrays nach einem anderen

  2. Sortieren mit SPL

  3. Stabile Sorte

Für die praktische Antwort unter Verwendung der vorhandenen Funktionen von PHP siehe 1., für die akademische ausführliche Antwort zu Sortieralgorithmen (welche Funktionen von PHP implementiert sind und welche Sie möglicherweise für wirklich, wirklich komplexe Fälle benötigen), siehe 2.

täuschen
quelle
@jterry Genau deshalb habe ich dies gemacht, um endlich eine gute Referenzfrage zu haben, gegen die ich schließen kann. Die individuelle Beantwortung jeder einzelnen Schneeflocke hilft niemandem. :)
täuschen
3
Ich denke, die Leute sollten sich einfach php.net ansehen
Alexander Jardim
@ Alex Ha! Absolut. Problem ist: niemand RTFM. : D
Täuschung
2
Wir haben diese Antworten bereits. Ich schlage vor, dass Sie die besten Antworten in jeder Antwort hier auflisten, anstatt den Inhalt zu duplizieren (oder neu zu schreiben). Auch Arrays werden in der Regel einzeln gesehen, so dass die Arbeit auf jeden Fall knapp gegen die Dupes stimmen muss.
hakre
1
@deceze: Wenn niemand RTFM, wird niemand auch RTFQA - die vorhandenen Q & A :)
hakre

Antworten:

164

Grundlegende eindimensionale Arrays

$array = array(3, 5, 2, 8);

Anwendbare Sortierfunktionen:

  • sort
  • rsort
  • asort
  • arsort
  • natsort
  • natcasesort
  • ksort
  • krsort

Der Unterschied zwischen diesen besteht lediglich darin, ob Schlüsselwertzuordnungen beibehalten werden (die " a" Funktionen), ob sie von niedrig nach hoch oder umgekehrt sortieren (" r"), ob sie Werte oder Schlüssel sortieren (" k") und wie sie Werte vergleichen (" nat" gegen normal). Eine Übersicht und Links zu weiteren Details finden Sie unter http://php.net/manual/en/array.sorting.php .

Mehrdimensionale Arrays, einschließlich Arrays von Objekten

$array = array(
    array('foo' => 'bar', 'baz' => 42),
    array('foo' => ...,   'baz' => ...),
    ...
);

Wenn Sie nach $arraydem Schlüssel 'foo' jedes Eintrags sortieren möchten , benötigen Sie eine benutzerdefinierte Vergleichsfunktion . Die obigen sortund verwandten Funktionen arbeiten mit einfachen Werten, die sie vergleichen und sortieren können. PHP ist nicht einfach „wissen“ , was mit einem tun komplexen Wert wie array('foo' => 'bar', 'baz' => 42)obwohl; Also musst du es sagen.

Dazu müssen Sie eine Vergleichsfunktion erstellen . Diese Funktion benötigt zwei Elemente und muss zurückgeben, 0wenn diese Elemente als gleich angesehen werden, einen niedrigeren Wert als 0den ersten Wert und einen höheren Wert als 0den ersten Wert. Das ist alles was benötigt wird:

function cmp(array $a, array $b) {
    if ($a['foo'] < $b['foo']) {
        return -1;
    } else if ($a['foo'] > $b['foo']) {
        return 1;
    } else {
        return 0;
    }
}

Oft möchten Sie eine anonyme Funktion als Rückruf verwenden. Wenn Sie eine Methode oder eine statische Methode verwenden möchten, sehen Sie sich die anderen Möglichkeiten zum Angeben eines Rückrufs in PHP an .

Sie verwenden dann eine der folgenden Funktionen:

Auch hier unterscheiden sie sich nur darin, ob sie Schlüssel-Wert-Zuordnungen beibehalten und nach Werten oder Schlüsseln sortieren. Lesen Sie die Dokumentation für Details.

Anwendungsbeispiel:

usort($array, 'cmp');

usortnimmt zwei Elemente aus dem Array und ruft Ihre cmpFunktion mit ihnen auf. So cmp()wird mit $aals array('foo' => 'bar', 'baz' => 42)und $bals einem anderen aufgerufen array('foo' => ..., 'baz' => ...). Die Funktion gibt dann zurück, usortwelcher der Werte größer war oder ob sie gleich waren. usortwiederholt diesen Vorgang und übergibt verschiedene Werte für $aund $bbis das Array sortiert ist. Die cmpFunktion wird viele Male aufgerufen, mindestens so oft, wie Werte vorhanden sind $array, mit unterschiedlichen Wertekombinationen für $aund $bjedes Mal.

Versuchen Sie Folgendes, um sich an diese Idee zu gewöhnen:

function cmp($a, $b) {
    echo 'cmp called with $a:', PHP_EOL;
    var_dump($a);
    echo 'and $b:', PHP_EOL;
    var_dump($b);
}

Sie haben lediglich eine benutzerdefinierte Methode zum Vergleichen von zwei Elementen definiert. Das ist alles, was Sie benötigen. Das funktioniert mit allen möglichen Werten.

Das funktioniert übrigens bei jedem Wert, die Werte müssen keine komplexen Arrays sein. Wenn Sie einen benutzerdefinierten Vergleich durchführen möchten, können Sie diesen auch für eine einfache Reihe von Zahlen durchführen.

sort sortiert nach Referenz und gibt nichts Nützliches zurück!

Beachten Sie, dass das Array an Ort und Stelle sortiert ist und Sie den Rückgabewert nichts zuweisen müssen. $array = sort($array)ersetzt das Array durch true, nicht durch ein sortiertes Array. Funktioniert einfach sort($array);.

Benutzerdefinierte numerische Vergleiche

Wenn Sie nach bazdem numerischen Schlüssel sortieren möchten, müssen Sie lediglich Folgendes tun:

function cmp(array $a, array $b) {
    return $a['baz'] - $b['baz'];
}

Dank The PoWEr of MATH wird ein Wert <0, 0 oder> 0 zurückgegeben, je nachdem, ob er kleiner$a , gleich oder größer als ist $b.

Beachten Sie, dass dies für floatWerte nicht gut funktioniert , da sie auf a reduziert werden intund an Genauigkeit verlieren. Verwenden Sie explizit -1, 0und das 1Rück stattdessen Werte.

Objekte

Wenn Sie über ein Array von Objekten verfügen, funktioniert dies auf folgende Weise:

function cmp($a, $b) {
    return $a->baz - $b->baz;
}

Funktionen

Innerhalb einer Vergleichsfunktion können Sie alles tun, was Sie brauchen, einschließlich der Aufruffunktionen:

function cmp(array $a, array $b) {
    return someFunction($a['baz']) - someFunction($b['baz']);
}

Saiten

Eine Verknüpfung für die erste String-Vergleichsversion:

function cmp(array $a, array $b) {
    return strcmp($a['foo'], $b['foo']);
}

strcmpmacht genau das, was von cmphier erwartet wird , es kehrt zurück -1, 0oder 1.

Raumschiffbetreiber

PHP 7 führte den Raumschiffoperator ein , der gleich / kleiner / größer als Vergleiche zwischen Typen vereinheitlicht und vereinfacht:

function cmp(array $a, array $b) {
    return $a['foo'] <=> $b['foo'];
}

Sortieren nach mehreren Feldern

Wenn Sie hauptsächlich nach sortieren möchten foo, aber wenn foofür zwei Elemente gleich ist, sortieren Sie nach baz:

function cmp(array $a, array $b) {
    if (($cmp = strcmp($a['foo'], $b['foo'])) !== 0) {
        return $cmp;
    } else {
        return $a['baz'] - $b['baz'];
    }
}

Für Vertraute entspricht dies einer SQL-Abfrage mit ORDER BY foo, baz.
Sehen Sie sich auch diese sehr übersichtliche Kurzfassung an und erfahren Sie, wie Sie eine solche Vergleichsfunktion dynamisch für eine beliebige Anzahl von Schlüsseln erstellen .

Sortieren in eine manuelle, statische Reihenfolge

Wenn Sie Elemente in einer "manuellen Reihenfolge" wie "foo", "bar", "baz" sortieren möchten :

function cmp(array $a, array $b) {
    static $order = array('foo', 'bar', 'baz');
    return array_search($a['foo'], $order) - array_search($b['foo'], $order);
}

Wenn Sie in allen oben genannten Fällen PHP 5.3 oder höher verwenden (und dies wirklich tun sollten), verwenden Sie anonyme Funktionen für kürzeren Code und um zu vermeiden, dass eine andere globale Funktion im Umlauf ist:

usort($array, function (array $a, array $b) { return $a['baz'] - $b['baz']; });

So einfach kann das Sortieren eines komplexen mehrdimensionalen Arrays sein. Denken Sie noch einmal daran, PHP beizubringen, wie man erkennt, welches der beiden Elemente "größer" ist . Lassen Sie PHP die eigentliche Sortierung durchführen.

Um zwischen aufsteigender und absteigender Reihenfolge zu wechseln, tauschen Sie einfach die Argumente $aund $bum. Z.B:

return $a['baz'] - $b['baz']; // ascending
return $b['baz'] - $a['baz']; // descending

Sortieren eines Arrays nach einem anderen

Und dann gibt es noch die Besonderheit array_multisort, mit der Sie ein Array nach einem anderen sortieren können:

$array1 = array( 4,   6,   1);
$array2 = array('a', 'b', 'c');

Das erwartete Ergebnis wäre hier:

$array2 = array('c', 'a', 'b');  // the sorted order of $array1

Verwenden Sie array_multisort, um dorthin zu gelangen:

array_multisort($array1, $array2);

Ab PHP 5.5.0 können Sie array_columneine Spalte aus einem mehrdimensionalen Array extrahieren und das Array nach dieser Spalte sortieren:

array_multisort(array_column($array, 'foo'), SORT_DESC, $array);

Ab PHP 7.0.0 können Sie auch Eigenschaften aus einem Array von Objekten extrahieren.


Wenn Sie häufigere Fälle haben, können Sie diese Antwort jederzeit bearbeiten.

täuschen
quelle
Die numerische Vergleichsfunktion funktioniert nicht für Float-Werte. Ich bin sicher, Sie wissen, was ich meine :)
Ja͢ck
1
Für die statische Reihenfolge würde ich eine array_flip()schnellere Positionssuche verwenden, z . B. $order[$a['foo']]anstelle von array_search($a['foo'], $order).
Ja͢ck
Könnte eine große Änderung sein : gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b, aber wenn Sie denken, dass es eine Verbesserung ist und ich alles Wesentliche aufgenommen habe, kann ich es anwenden.
Rizier123
@ Rizier123 Ich begrüße die Mühe auf jeden Fall, es ist eine sehr gute Zusammenfassung; aber ich würde es vorziehen, wenn Sie es als separate Antwort posten würden, auch wenn es sehr ähnlich ist. Ihr Umschreiben enthält viele Details (Referenzübergabe, große Tabelle usw.), aber dieses Detail lenkt von der reibungslosen Einführung in das Kernthema der Funktionsweise der Vergleichsfunktion IMHO ab. Ich beziehe mich absichtlich mehrmals ausdrücklich auf das Handbuch, da dort solche Details nachgeschlagen werden sollten. Sie müssen es hier nicht wiederholen und von der Kernidee ablenken, die ich zu vermitteln versuche.
Täuschung
@deceze Die größte Herausforderung besteht darin, die Informationen so kompakt und lesbar wie möglich anzuzeigen und den Benutzern das Auffinden ihrer Sortierfunktion zu erleichtern. Ich habe ein paar Dinge optimiert : gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b, aber ich muss noch darüber nachdenken, ob es nützlich und wertvoll ist, es als separate Antwort zu veröffentlichen, da es sehr ähnlich ist
Rizier123
139

Nun, die meisten grundlegenden Methoden sind bereits durch Täuschung abgedeckt. Ich würde versuchen, andere Arten von Sorten zu betrachten

Sortieren mit SPL

SplHeap

class SimpleHeapSort extends SplHeap {
    public function compare($a, $b) {
        return strcmp($a, $b);
    }
}

// Let's populate our heap here (data of 2009)
$heap = new SimpleHeapSort();
$heap->insert("a");
$heap->insert("b");
$heap->insert("c");

echo implode(PHP_EOL, iterator_to_array($heap));

Ausgabe

c
b
a

SplMaxHeap

Die SplMaxHeap-Klasse bietet die Hauptfunktionen eines Heaps und hält das Maximum oben.

$heap = new SplMaxHeap();
$heap->insert(1);
$heap->insert(2);
$heap->insert(3);

SplMinHeap

Die SplMinHeap-Klasse bietet die Hauptfunktionen eines Heaps, wobei das Minimum oben bleibt.

$heap = new SplMinHeap ();
$heap->insert(3);
$heap->insert(1);
$heap->insert(2);

Andere Arten der Sortierung

Blasensortierung

Aus dem Wikipedia-Artikel über Bubble Sort:

Die Blasensortierung, die manchmal fälschlicherweise als sinkende Sortierung bezeichnet wird, ist ein einfacher Sortieralgorithmus, bei dem die zu sortierende Liste wiederholt durchlaufen wird, jedes Paar benachbarter Elemente verglichen und ausgetauscht wird, wenn sie in der falschen Reihenfolge vorliegen. Der Durchlauf durch die Liste wird wiederholt, bis keine Swaps mehr erforderlich sind, was darauf hinweist, dass die Liste sortiert ist. Der Algorithmus erhält seinen Namen von der Art und Weise, wie kleinere Elemente an die Spitze der Liste "sprudeln". Da nur Vergleiche zum Bearbeiten von Elementen verwendet werden, handelt es sich um eine Vergleichssortierung. Obwohl der Algorithmus einfach ist, sind die meisten anderen Sortieralgorithmen für große Listen effizienter.

function bubbleSort(array $array) {
    $array_size = count($array);
    for($i = 0; $i < $array_size; $i ++) {
        for($j = 0; $j < $array_size; $j ++) {
            if ($array[$i] < $array[$j]) {
                $tem = $array[$i];
                $array[$i] = $array[$j];
                $array[$j] = $tem;
            }
        }
    }
    return $array;
}

Auswahl sortieren

Aus dem Wikipedia-Artikel über Auswahl sortieren:

In der Informatik ist die Auswahlsortierung ein Sortieralgorithmus, insbesondere eine In-Place-Vergleichssortierung. Es hat eine O (n2) -Zeitkomplexität, was es auf großen Listen ineffizient macht, und es ist im Allgemeinen schlechter als die ähnliche Einfügesortierung. Die Auswahlsortierung zeichnet sich durch ihre Einfachheit aus und bietet in bestimmten Situationen Leistungsvorteile gegenüber komplizierteren Algorithmen, insbesondere wenn der Hilfsspeicher begrenzt ist.

function selectionSort(array $array) {
    $length = count($array);
    for($i = 0; $i < $length; $i ++) {
        $min = $i;
        for($j = $i + 1; $j < $length; $j ++) {
            if ($array[$j] < $array[$min]) {
                $min = $j;
            }
        }
        $tmp = $array[$min];
        $array[$min] = $array[$i];
        $array[$i] = $tmp;
    }
    return $array;
}

Sortieren durch Einfügen

Aus dem Wikipedia-Artikel über Einfügungssortierung:

Die Einfügesortierung ist ein einfacher Sortieralgorithmus, mit dem das endgültig sortierte Array (oder die Liste) einzeln erstellt wird. Bei großen Listen ist es viel weniger effizient als bei fortgeschritteneren Algorithmen wie Quicksort, Heapsort oder Merge-Sortierung. Die Einfügesortierung bietet jedoch mehrere Vorteile:

function insertionSort(array $array) {
    $count = count($array);
    for($i = 1; $i < $count; $i ++) {

        $j = $i - 1;
        // second element of the array
        $element = $array[$i];
        while ( $j >= 0 && $array[$j] > $element ) {
            $array[$j + 1] = $array[$j];
            $array[$j] = $element;
            $j = $j - 1;
        }
    }
    return $array;
}

Shellsort

Aus dem Wikipedia-Artikel über Shellsort:

Shellsort, auch als Shell-Sortierung oder Shell-Methode bekannt, ist eine direkte Vergleichssortierung. Es verallgemeinert eine austauschbare Sortierung, wie z. B. Einfügen oder Blasensortierung, indem der Vergleich und Austausch von Elementen mit weit auseinander liegenden Elementen gestartet wird, bevor mit benachbarten Elementen abgeschlossen wird.

function shellSort(array $array) {
    $gaps = array(
            1,
            2,
            3,
            4,
            6
    );
    $gap = array_pop($gaps);
    $length = count($array);
    while ( $gap > 0 ) {
        for($i = $gap; $i < $length; $i ++) {
            $tmp = $array[$i];
            $j = $i;
            while ( $j >= $gap && $array[$j - $gap] > $tmp ) {
                $array[$j] = $array[$j - $gap];
                $j -= $gap;
            }
            $array[$j] = $tmp;
        }
        $gap = array_pop($gaps);
    }
    return $array;
}

Kammsortierung

Aus dem Wikipedia-Artikel über Kammsortierung:

Die Kammsortierung ist ein relativ einfacher Sortieralgorithmus, der ursprünglich 1980 von Wlodzimierz Dobosiewicz entwickelt wurde. Später wurde er 1991 von Stephen Lacey und Richard Box wiederentdeckt. Die Kammsortierung verbessert die Blasensortierung.

function combSort(array $array) {
    $gap = count($array);
    $swap = true;
    while ( $gap > 1 || $swap ) {
        if ($gap > 1)
            $gap /= 1.25;
        $swap = false;
        $i = 0;
        while ( $i + $gap < count($array) ) {
            if ($array[$i] > $array[$i + $gap]) {
                // swapping the elements.
                list($array[$i], $array[$i + $gap]) = array(
                        $array[$i + $gap],
                        $array[$i]
                );
                $swap = true;
            }
            $i ++;
        }
    }
    return $array;
}

Zusammenführen, sortieren

Aus dem Wikipedia-Artikel über Zusammenführen sortieren:

In der Informatik ist eine Zusammenführungssortierung (auch häufig als Zusammenführungssortierung bezeichnet) ein O (n log n) -vergleichsbasierter Sortieralgorithmus. Die meisten Implementierungen erzeugen eine stabile Sortierung, was bedeutet, dass die Implementierung die Eingabereihenfolge gleicher Elemente in der sortierten Ausgabe beibehält

function mergeSort(array $array) {
    if (count($array) <= 1)
        return $array;

    $left = mergeSort(array_splice($array, floor(count($array) / 2)));
    $right = mergeSort($array);

    $result = array();

    while ( count($left) > 0 && count($right) > 0 ) {
        if ($left[0] <= $right[0]) {
            array_push($result, array_shift($left));
        } else {
            array_push($result, array_shift($right));
        }
    }
    while ( count($left) > 0 )
        array_push($result, array_shift($left));

    while ( count($right) > 0 )
        array_push($result, array_shift($right));

    return $result;
}

Schnelle Sorte

Aus dem Wikipedia-Artikel über Quicksort:

Quicksort oder Partition-Exchange-Sortierung ist ein von Tony Hoare entwickelter Sortieralgorithmus, der im Durchschnitt O (n log n) Vergleiche zum Sortieren von n Elementen durchführt. Im schlimmsten Fall werden O (n2) -Vergleiche durchgeführt, obwohl dieses Verhalten selten ist.

function quickSort(array $array) {
    if (count($array) == 0) {
        return $array;
    }
    $pivot = $array[0];
    $left = $right = array();
    for($i = 1; $i < count($array); $i ++) {
        if ($array[$i] < $pivot) {
            $left[] = $array[$i];
        } else {
            $right[] = $array[$i];
        }
    }
    return array_merge(quickSort($left), array(
            $pivot
    ), quickSort($right));
}

Permutationssortierung

Aus dem Wikipedia-Artikel über Permutation sort:

Permutationssortierung, bei der die möglichen Permutationen des Eingabearrays / der Eingabeliste generiert werden, bis die sortierte gefunden wird.

function permutationSort($items, $perms = array()) {
    if (empty($items)) {
        if (inOrder($perms)) {
            return $perms;
        }
    } else {
        for($i = count($items) - 1; $i >= 0; -- $i) {
            $newitems = $items;
            $newperms = $perms;
            list($foo) = array_splice($newitems, $i, 1);
            array_unshift($newperms, $foo);
            $res = permutationSort($newitems, $newperms);
            if ($res) {
                return $res;
            }
        }
    }
}

function inOrder($array) {
    for($i = 0; $i < count($array); $i ++) {
        if (isset($array[$i + 1])) {
            if ($array[$i] > $array[$i + 1]) {
                return False;
            }
        }
    }
    return True;
}

Radix sort

Aus dem Wikipedia-Artikel über Radix sort:

In der Informatik ist die Radix-Sortierung ein nicht vergleichender ganzzahliger Sortieralgorithmus, der Daten mit ganzzahligen Schlüsseln sortiert, indem Schlüssel nach den einzelnen Ziffern gruppiert werden, die dieselbe signifikante Position und denselben Wert haben.

// Radix Sort for 0 to 256
function radixSort($array) {
    $n = count($array);
    $partition = array();

    for($slot = 0; $slot < 256; ++ $slot) {
        $partition[] = array();
    }

    for($i = 0; $i < $n; ++ $i) {
        $partition[$array[$i]->age & 0xFF][] = &$array[$i];
    }

    $i = 0;

    for($slot = 0; $slot < 256; ++ $slot) {
        for($j = 0, $n = count($partition[$slot]); $j < $n; ++ $j) {
            $array[$i ++] = &$partition[$slot][$j];
        }
    }
    return $array;
}
Baba
quelle
4
@deceze du hast alle Grundlagen abgedeckt .. ich musste nach einem anderen Weg suchen, um relevant zu sein :)
Baba
5
Ich sehe nichts falsches an den akademischeren Sortiermethoden :) Viel weniger nützlich für die meisten Anwendungen, aber gelegentlich können sie gefragt / benötigt werden, um eine Referenz zu haben, zumal ich die meisten davon im Laufe der Zeit vergessen habe
Dave
Für eine schnelle Sortierung wird empfohlen, Pivot als Median aus drei Werten auszuwählen : erstes, mittleres und letztes Element . Dies ist mein Beispiel für die Pivot-Auswahl. Dies ermöglicht es, ein im schlimmsten Fall umgekehrt sortiertes Array zu vermeiden (was zu O(n^2)Vergleichen führt, wenn nur das erste Element als Drehpunkt verwendet wird)
Alma Do
Ich habe gehört, dass spl schneller funktioniert als normale Array-Sortierung. Stimmt das?
Jewelhuq
Ich stimme Dave zu, heutzutage haben fast einige davon aufgenommen, warum ich mich selten daran erinnere oder es benutze.
Mike Nguyen
43

Stabile Sorte

Angenommen, Sie haben ein Array wie dieses:

['Kale', 'Kaleidoscope', 'Aardvark', 'Apple', 'Leicester', 'Lovely']

Und jetzt möchten Sie nur nach dem ersten Buchstaben sortieren:

usort($array, function($a, $b) {
    return strcmp($a[0], $b[0]);
});

Das Ergebnis ist folgendes:

['Apple', 'Aardvark', 'Kale', 'Kaleidoscope', 'Lovely', 'Leicester']

Die Sorte war nicht stabil!

Der aufmerksame Beobachter hat möglicherweise bemerkt, dass der Array-Sortieralgorithmus (QuickSort) kein stabiles Ergebnis liefert und dass die ursprüngliche Reihenfolge zwischen Wörtern desselben Anfangsbuchstabens nicht beibehalten wurde. Dieser Fall ist trivial und wir hätten die gesamte Zeichenfolge vergleichen sollen, aber nehmen wir an, dass Ihr Anwendungsfall komplizierter ist, z. B. zwei aufeinanderfolgende Sortierungen in verschiedenen Feldern, die die Arbeit des anderen nicht aufheben sollten.

Die Schwartzsche Transformation

Die Schwartzsche Transformation , auch als Dekorations-Sortier-Undekorations-Redewendung bezeichnet, bewirkt eine stabile Sortierung mit einem inhärent instabilen Sortieralgorithmus.

Zunächst dekorieren Sie jedes Array-Element mit einem anderen Array, das einen Primärschlüssel (den Wert) und einen Sekundärschlüssel (seinen Index oder seine Position) umfasst:

array_walk($array, function(&$element, $index) {
    $element = array($element, $index); // decorate
});

Dies transformiert das Array in Folgendes:

[
    ['Kale', 0], ['Kaleidoscope', 1], 
    ['Aardvark', 2], ['Apple', 3], 
    ['Leicester', 4], ['Lovely', 5]
]

Jetzt passen wir den Vergleichsschritt an; Wir vergleichen den ersten Buchstaben erneut, aber wenn sie gleich sind, wird der Sekundärschlüssel verwendet, um die ursprüngliche Reihenfolge beizubehalten:

usort($array, function($a, $b) {
    // $a[0] and $b[0] contain the primary sort key
    // $a[1] and $b[1] contain the secondary sort key
    $tmp = strcmp($a[0][0], $b[0][0]);

    if ($tmp != 0) {
        return $tmp; // use primary key comparison results
    }

    return $a[1] - $b[1]; // use secondary key
});

Danach dekorieren wir:

array_walk($array, function(&$element) {
    $element = $element[0];
});

Das Endergebnis:

['Aardvark', 'Apple', 'Kale', 'Kaleidoscope', 'Leicester', 'Lovely']

Was ist mit Wiederverwendung?

Sie mussten Ihre Vergleichsfunktion neu schreiben, um mit den transformierten Array-Elementen arbeiten zu können. Möglicherweise möchten Sie Ihre heiklen Vergleichsfunktionen nicht bearbeiten. Hier ist ein Wrapper für die Vergleichsfunktion:

function stablecmp($fn)
{
    return function($a, $b) use ($fn) {
        if (($tmp = call_user_func($fn, $a[0], $b[0])) != 0) {
            return $tmp;
        } else {
            return $a[1] - $b[1];
        }
    };
}

Schreiben wir den Sortierschritt mit dieser Funktion:

usort($array, stablecmp(function($a, $b) {
    return strcmp($a[0], $b[0]);
}));

Voila! Ihr makelloser Vergleichscode ist zurück.

Jack
quelle
Ihr Satz "bewirkt eine stabile Sortierung mit einem inhärent instabilen Sortieralgorithmus" war für mich der ah-ha-Moment. Auf der Wikipedia-Seite wird das Wort Stall nicht erwähnt, was mir die Schönheit der Transformation zu sein scheint. Schande.
Tyler Collier
1
@ TylerCollier Ja, Sie müssen zwischen den Zeilen dieser Wikipedia-Referenz lesen ... Ich habe Ihnen die Mühe
erspart, dies zu
15

Ab PHP 5.3 mit Closures ist es auch möglich, einen Closure zu verwenden, um die Reihenfolge Ihrer Sortierung zu bestimmen.

Angenommen, $ array ist ein Array von Objekten, die eine month-Eigenschaft enthalten.

 $orderArray = array("Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec");

 usort($array, function($a, $b) use ($orderArray){
       return array_search($a->month, $orderArray) - array_search($b->month, $orderArray);
 }); 
Orangenpille
quelle
Denken Sie daran, dass dadurch jede vorherige relative Reihenfolge entfernt wird (z. B. kann das erste "Juli" -Objekt in der vorsortierten Liste nach dem Sortieren am Ende der Gruppe der Juli-Objekte landen). Siehe "Stabile Sortierung" oben.
George Langley
9

LINQ

In .NET wird LINQ häufig zum Sortieren verwendet, was eine viel bessere Syntax gegenüber Vergleichsfunktionen bietet, insbesondere wenn Objekte nach mehreren Feldern sortiert werden müssen. Es gibt mehrere Ports von LINQ zu PHP, einschließlich der YaLinqo- Bibliothek *. Damit können Arrays mit einer einzigen Zeile sortiert werden, ohne komplexe Vergleichsfunktionen zu schreiben.

$sortedByName         = from($objects)->orderBy('$v->name');
$sortedByCount        = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');

Vergleiche können weiter angepasst werden, indem ein Rückruf als zweites Argument übergeben wird, zum Beispiel:

$sortedByFilenameNat  = from($objects)->orderBy('$v->filename', 'strnatcmp');

Hier '$v->count'ist eine Abkürzung für function ($v) { return $v->count; }(entweder kann verwendet werden). Diese Methodenketten geben Iteratoren zurück. Iteratoren können bei Bedarf durch Hinzufügen ->toArray()am Ende in Arrays umgewandelt werden .

Intern orderByund verwandte Methoden aufrufen entsprechenden Array Sortierfunktionen ( uasort, krsort, multisort, usortetc.).

LINQ enthält viele weitere Methoden, die von SQL inspiriert sind: Filtern, Gruppieren, Verbinden, Aggregieren usw. Es eignet sich am besten für Fälle, in denen komplexe Transformationen für Arrays und Objekte durchgeführt werden müssen, ohne auf Datenbanken angewiesen zu sein.

* Von mir entwickelt, siehe Readme für weitere Details und Vergleich mit anderen LINQ-Ports

Athari
quelle
3

Mehrdimensionale Sortierung nach Schlüsselwert

Natürliche Art eines mehrdimensionalen Arrays durch einen Schlüsselwert und behalten Sie auch die ursprüngliche Reihenfolge bei (mischen Sie nicht die Hauptschlüssel):

function multisortByKeyValue( $k, $arr ) {
    $ids   = array();
    $index = 1;

    foreach ( $arr as $key => $row ) {
        $ids[ $key ] = intval( $row[ $k ] ) . '-' . $index . '-' . $key;
        $index ++;
    }

    natsort( $ids );

    $arr = array_merge( $ids, $arr );

    return $arr;
}

Testfall:

$arr = array(
    'id1' => array(
        'label'    => 'ID 1',
        'priority' => 30,
    ),
    'id2' => array(
        'label'    => 'ID 2',
        'priority' => 70,
    ),
    'id3' => array(
        'label'    => 'ID 3',
        'priority' => 20,
    ),
    'id4' => array(
        'label'    => 'ID 4',
        'priority' => 30,
    ),
);

$sorted = multisortByKeyValue( 'priority', $arr );

// $sorted equals to:
/*
array (
  'id3' => array (
    'label' => 'ID 3',
    'priority' => 20,
  ),
  'id1' => array (
    'label' => 'ID 1',
    'priority' => 30,
  ),
  'id4' => array (
    'label' => 'ID 4',
    'priority' => 30,
  ),
  'id2' => array (
    'label' => 'ID 2',
    'priority' => 70,
  ),
)
*/
Andrew Surdu
quelle
2

Es ist sehr praktisch, Arrays mit sortierter Funktion von Nspl aus zu sortieren :

Grundlegende Sortierung

// Sort array
$sorted = sorted([3, 1, 2]);

// Sort array in descending order
$sortedDesc = sorted([3, 1, 2], true);

Sortieren nach Funktionsergebnis

// Sort array by the result of a given function (order words by length)
$sortedByLength = sorted(['bc', 'a', 'abc'], 'strlen');
$sortedByLengthDesc = sorted(['bc', 'a', 'abc'], true, 'strlen');

// Sort array by the result of user-defined function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], function($v) { return $v[0]; }); 

// Which is the same as
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], itemGetter(0));
$sortedByTheFirstCharacterDesc = sorted(['bc', 'a', 'abc'], true, itemGetter(0));

// itemGetter(0) returns a function which takes an argument with access by index/key
// and returns the value at index 0

Mehrdimensionales Array sortieren

// Sort multidimensional array (sort list of users by their names)
$users = [
    array('name' => 'Robert', 'age' => 20),
    array('name' => 'Alex', 'age' => 30),
    array('name' => 'Jack', 'age' => 25),
];
$sortedByName = sorted($users, itemGetter('name'));
$sortedByNameDesc = sorted($users, true, itemGetter('name'));

// itemGetter('name') returns a function which takes an argument with access by index/key
// and returns the value of the 'name' key

Array von Objekten sortieren

// Lets assume we have class User(name, age) with properties name and age
// and public methods getName() and getAge()
$users = [
    new User('Robert', 20),
    new User('Alex', 30),
    new User('Jack', 25),
];

// Sort list of objects by property value (sort list of users by their name)
$sortedByName = sorted($users, propertyGetter('name'));
$sortedByNameDesc = sorted($users, true, propertyGetter('name'));

// propertyGetter('name') returns a function which takes an object
// and returns the value of its 'name' property

// Sort list of objects by method result (sort list of users by their age)
$sortedByAge = sorted($users, methodCaller('getAge'));
$sortedByAgeDesc = sorted($users, true, methodCaller('getAge'));

// methodCaller('getAge') returns a function which takes an object
// and returns the result of its getAge() method

Sortieren mit einer Vergleichsfunktion

// Sort with a comparison function (order words lexicographically with strcmp)
$sortedLexicographically = sorted(['bc', 'a', 'abc'], false, null, 'strcmp');

// Sort with user-defined comparison function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], false, null, function($v1, $v2) {
    return chr($v1[0]) - chr($v2[0]);
});

Sie können alle diese Beispiele hier sehen .

Ihor Burlachenko
quelle
2

Wenn Sie nach dem Schlüsselwert bestellen möchten, können Sie dies in einer Zeile tun, elegant und klar. Dies wird nach dem Preis aufsteigend bestellt. Verwendet array_multisort und array_column.

   Array([0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => coffee [price] => 9.99 ) [2] => Array ( [name] => rice [price] => 4.04 ) )

   array_multisort (array_column($array, 'price'), SORT_ASC, $array);

produzieren

     Array ( [0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => rice [price] => 4.04 ) [2] => Array ( [name] => coffee [price] => 9.99 ) )
GAV
quelle
1

Diese Seite ist sehr umfangreich, aber ich möchte noch etwas mehr über den großartigen Nutzen des Raumschiff-Operators (Drei-Wege-Vergleichsoperator) hinzufügen - eines schönen Kindes von PHP7 +.

Verwenden des Raumschiffoperators zum Implementieren mehrerer Sortierbedingungen

Dies macht große Fortschritte bei der Reduzierung des Aufblähens von Code und der Verbesserung der Lesbarkeit.

Wenn Sie Ihre benutzerdefinierte Sortierfunktion ( usort()/ uasort()/ uksort()) schreiben, um mehrere Bedingungen zu verarbeiten, müssen Sie nur ausgeglichene Arrays auf beiden Seiten des Operators schreiben und das Ergebnis zurückgeben. Keine verschachtelten Bedingungsblöcke oder Mehrfachrückgaben mehr.

Die Elemente von beiden Seiten des Bedieners werden nacheinander von links nach rechts durchlaufen und die Auswertung zurückgegeben, sobald eine Nichtbindung festgestellt wird oder wenn alle Elemente verglichen wurden.

Beispieldaten für meine Demonstrationen:

$multidimArray = [
    'a' => [
        'boolean' => true,
        'natString' => 'text10',
        'object' => (object)['prop' => 2],
        'float' => -.5,
        'mixed' => []
    ],
    'b' => [
        'boolean' => true,
        'natString' => 'text12',
        'object' => (object)['prop' => 4],
        'float' => 0,
        'mixed' => null
    ],
    'c' => [
        'boolean' => false,
        'natString' => 'text100',
        'object' => (object)['prop' => 9],
        'float' => -.5,
        'mixed' => false
    ],
    'd' => [
        'boolean' => true,
        'natString' => 'text1',
        'object' => (object)['prop' => 9],
        'float' => -5,
        'mixed' => "\0"
    ],
    'e' => [
        'boolean' => false,
        'natString' => 'text2',
        'object' => (object)['prop' => 2],
        'float' => .5,
        'mixed' => ''
    ]
];

Demonstrationen (um ein Aufblähen der Stackoverflow-Seite zu vermeiden, lesen Sie bitte den Demo-Link für die Ausgaben):

  • Sortierlogik:

    1. Boolescher DESC (false = 0, true = 1, also wahr vor falsch)
    2. float ASC

      uasort($multidimArray, function($a, $b) {
          return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']];
      });
  • Sortierlogik:

    1. gemischtes ASC
    2. Objekt ASC
    3. Boolescher ASC

      uasort($multidimArray, function($a, $b) {
          return [$a['mixed'], $a['object']->prop, $a['boolean']] <=> [$b['mixed'], $b['object']->prop, $b['boolean']];
      });
  • Sortierlogik:

    1. Eigenschaftsanzahl des Objekts ASC
    2. Iterierbarkeit von gemischtem DESC
    3. natString Länge ASC
    4. natString ASC

      uasort($multidimArray, function($a, $b) {
          return [count(get_object_vars($a['object'])), is_iterable($a['mixed']), strlen($a['natString']), $a['natString']]
                 <=>
                 [count(get_object_vars($b['object'])), is_iterable($b['mixed']), strlen($b['natString']), $b['natString']];
      });

Mit dieser Syntax können Sie Werte, funktionale Ergebnisse, tief verschachtelte Daten und Sortierrichtungen auf elegante Weise sortieren. Es lohnt sich auf jeden Fall, in Ihr PHP-Toolbelt einzusteigen ... für Fälle, in denen Sie Daten außerhalb der Datenbank verarbeiten - natürlich wäre SQL eine viel sinnvollere Technik.

Ab PHP7.4 können Sie nach eigenem Ermessen die Pfeilsyntax mit diesen anonymen Funktionen verwenden. Gleiches Skript mit Pfeilsyntax .

mickmackusa
quelle
0

Wenn jemand eine einfachere Lösung für die Bearbeitung von Arrays wünscht, verwenden Sie einfach das Laravel Collection-Paket mit einer implementierten sortBy-Funktion, mit der Sie einfach nach Schlüsseln sortieren können.

$collection->sortBy('forename')->sortBy('surname');

dh, um zuerst nach a, dann nach b und dann nach c zu sortieren, wäre die richtige Klausel

sortBy('c')->sortBy('b')->sortBy('a')

https://packagist.org/packages/tightenco/collect

Rizerzero
quelle
-1

Es gibt verschiedene Möglichkeiten, ein Array zu sortieren. Ich werde einige Methoden für diese Aufgabe erwähnen. Zunächst einmal werde ich ein ganzzahliges Array angeben, das als '$ numbers' bezeichnet wird.

$number = array(8,9,3,4,0,1,2);

Dies ist der normale Weg zum Erstellen eines Arrays. Angenommen, ich möchte dieses Array in aufsteigender Reihenfolge sortieren. Dafür kann die Methode 'sort ()' verwendet werden.

<?php

    $number = array(8,9,3,4,0,1,2);
    sort($number);

   foreach ($number as $value) {
       echo $value."  ";
   }
?>

Betrachten Sie nun die Ausgabe davon,

Geben Sie hier die Bildbeschreibung ein

Sie können sehen, dass das gedruckte Nummernfeld sortiert ist. Wenn das Nummernarray in absteigender Reihenfolge sortiert werden soll, kann für diese Aufgabe die Methode 'rsort ()' verwendet werden.

<?php

     $number = array(8,9,3,4,0,1,2);
     rsort($number);

     foreach ($number as $value) {
        echo $value."  ";
     }
?>

Betrachten Sie die Ausgabe ..

Geben Sie hier die Bildbeschreibung ein

Jetzt wird das Array in absteigender Reihenfolge sortiert. Okay, betrachten wir ein assoziatives Array. Ich gebe ein assoziatives Array (assoziatives Array bedeutet, dass ein Array, dessen jeder Index einen eindeutigen Schlüsselwert hat) wie folgt:

$number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);

Nun möchte ich dieses Array in aufsteigender Reihenfolge nach ihrem Wert sortieren. Dafür kann die Methode 'asort ()' verwendet werden.

<?php

   $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
   asort($number);

   foreach ($number as $value) {
      echo $value."  ";
    }
?>

Wenn Sie die absteigende Reihenfolge nach ihrem Wert sortieren, kann die Methode 'arsort ()' verwendet werden. Angenommen, Sie möchten dieses Array nach seinem Schlüsselwert sortieren. In diesem Fall kann die Methode 'ksort ()' verwendet werden.

<?php

     $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
     ksort($number);

     foreach ($number as $value) {
         echo $value."  ";
     }
?>

Betrachten Sie nun die Ausgabe. Geben Sie hier die Bildbeschreibung ein

Jetzt wird das Array nach seinem Schlüsselwert sortiert. Wenn Sie das Array in absteigender Reihenfolge nach ihrem Schlüsselwert sortieren möchten, kann die Methode 'krsort ()' verwendet werden.

<?php

    $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
    krsort($number);

    foreach ($number as $value) {
       echo $value."  ";
    }
?>

Jetzt wird das assoziative Array in absteigender Reihenfolge nach seinem Schlüsselwert sortiert. Sehen Sie sich die Ausgabe an. Geben Sie hier die Bildbeschreibung ein

Dies sind einige Methoden zum Sortieren eines Arrays in aufsteigender oder absteigender Reihenfolge in PHP. Ich hoffe, Sie könnten eine Idee bekommen. Danke!

GT_hash
quelle
Deceze deckt diese Erkenntnisse nicht bereits ab mit: "Der Unterschied zwischen diesen besteht lediglich darin, ob Schlüsselwertassoziationen beibehalten werden (die" a "-Funktionen), ob sie von niedrig nach hoch oder umgekehrt sortieren (" r "), ob sie sortiert Werte oder Schlüssel ("k") und vergleicht Werte ("nat" vs. normal). " in der akzeptierten Antwort?
Mickmackusa
-2

Am einfachsten ist es, die Funktion usort zu verwenden, um das Array ohne Schleifen zu sortieren: Nachfolgend finden Sie ein Beispiel:

   $array_compare= array("0" =>4,"1"=>2,"2"=>500,"3"=>100);

Dies wird in absteigender Reihenfolge sortiert:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) > 0 ? 1 :-1;
    });

Dies wird in aufsteigender Reihenfolge sortiert:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) < 0 ? 1 :-1;
    });
pihu
quelle
1
1) Das Beispiel und der Code sind inkonsistent. 2) Dies wird in den obigen Antworten bereits ausführlich erklärt. 3) Versuchen Sie möglicherweise, auf eine andere Frage zu antworten?
Täuschung