608 Stimmen

Wie sortiert man ein Array von assoziativen Arrays nach dem Wert eines bestimmten Schlüssels in PHP?

Angesichts dieser Anordnung:

$inventory = array(

   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),
   array("type"=>"pork", "price"=>5.43),

);

Ich möchte sortieren $inventory Elemente nach Preis zu erhalten:

$inventory = array(

   array("type"=>"pork", "price"=>5.43),
   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),

);

Wie kann ich das tun?

3 Stimmen

1 Stimmen

Warum strukturieren Sie Ihr Eingabefeld nicht einfach so um, dass die price Spalte steht an erster Stelle und type an zweiter Stelle? Auf diese Weise können Sie einfach aufrufen rsort() . 3v4l.org/2meqs

0 Stimmen

801voto

Josh Davis Punkte 27450

Sie haben Recht, die gesuchte Funktion ist array_multisort() .

Hier ist ein Beispiel, das direkt aus dem Handbuch entnommen und an Ihren Fall angepasst wurde:

$price = array();
foreach ($inventory as $key => $row)
{
    $price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);

Seit PHP 5.5.0 können Sie array_column() anstelle dieser foreach:

$price = array_column($inventory, 'price');

array_multisort($price, SORT_DESC, $inventory);

6 Stimmen

Allerdings ist dies definitiv teurer als die Alternativen.

9 Stimmen

Teurer? Das ist seltsam, auf meinem Rechner (mit PHP 5.3.1-dev) ist array_multisort() ein paar Prozent schneller bei kleinen Arrays und bis zu 100 mal schneller bei großen Arrays (100+ Elemente)

3 Stimmen

Es sollte keine Änderungen erfordern, um mit numerischen Tasten zu arbeiten. Wenn Sie auf einen Fehler oder ein merkwürdiges Verhalten im Zusammenhang mit den Zifferntasten stoßen, stellen Sie eine neue Frage.

514voto

Mark Amery Punkte 124946

PHP 7+

Ab PHP 7 kann dies kurz und bündig mit usort mit einer anonyme Funktion die den Raumschiffbetreiber um Elemente zu vergleichen.

Sie können eine aufsteigende Sortierung wie folgt vornehmen:

usort($inventory, function ($item1, $item2) {
    return $item1['price'] <=> $item2['price'];
});

Oder eine absteigende Art wie diese:

usort($inventory, function ($item1, $item2) {
    return $item2['price'] <=> $item1['price'];
});

Um zu verstehen, wie das funktioniert, muss man wissen, dass usort nimmt eine vom Benutzer bereitgestellte Vergleichsfunktion, die sich wie folgt verhalten muss (aus den Dokumenten):

Die Vergleichsfunktion muss eine ganze Zahl zurückgeben, die kleiner, gleich oder größer als Null ist, wenn das erste Argument als kleiner, gleich oder größer als das zweite betrachtet wird.

Und beachten Sie auch, dass <=> der Raumschiffbetreiber,

gibt 0 zurück, wenn beide Operanden gleich sind, 1, wenn der linke größer ist, und -1, wenn der rechte größer ist

was genau das ist, was usort Bedürfnisse. In der Tat ist fast die gesamte Begründung für die Aufnahme von <=> zur Sprache in https://wiki.php.net/rfc/combined-comparison-operator ist, dass es

macht das Schreiben von Bestellrückrufen für die Verwendung mit usort() einfacher


PHP 5.3+

Mit PHP 5.3 wurden anonyme Funktionen eingeführt, aber es gibt noch nicht den Raumschiff-Operator. Wir können immer noch usort um unser Array zu sortieren, aber es ist etwas ausführlicher und schwieriger zu verstehen:

usort($inventory, function ($item1, $item2) {
    if ($item1['price'] == $item2['price']) return 0;
    return $item1['price'] < $item2['price'] ? -1 : 1;
});

Beachten Sie, dass es für Komparatoren, die mit Integer-Werten arbeiten, zwar üblich ist, nur die Differenz der Werte zurückzugeben, wie $item2['price'] - $item1['price'] wir kann nicht in diesem Fall sicher tun. Das liegt daran, dass die Preise im Beispiel des Fragestellers Fließkommazahlen sind, aber die Vergleichsfunktion, die wir an usort muss ganze Zahlen zurückgeben für usort richtig zu funktionieren:

Rücksendung nicht-ganzzahlig Werte aus der Vergleichsfunktion, wie z.B. float, führen zu einer internen Umwandlung des Rückgabewerts des Callbacks in integer. Werte wie 0,99 und 0,1 werden also beide in einen Integer-Wert von 0 umgewandelt, wodurch diese Werte als gleichwertig verglichen werden.

Dies ist ein wichtiger Fallstrick, der bei der Verwendung von usort in PHP 5.x! Meine ursprüngliche Version dieser Antwort Ich habe diesen Fehler gemacht, und trotzdem habe ich zehn Upvotes bei Tausenden von Aufrufen erhalten, ohne dass jemand den schwerwiegenden Fehler bemerkt hat. Die Leichtigkeit, mit der Trottel wie ich Komparatorfunktionen vermasseln können, ist genau der Grund dafür, dass in PHP 7 der einfacher zu verwendende Raumschiff-Operator in die Sprache aufgenommen wurde.

15 Stimmen

Tut mir leid, aber dieser Ansatz löscht die String-Schlüssel aus assoziativen Arrays. Stattdessen sollte die Funktion "uasort" verwendet werden.

13 Stimmen

@DotMat Interessant - das wusste ich nicht uasort . Nach einem Blick in die Dokumente ist diese Antwort jedoch immer noch richtig in diesem Fall . Im Beispiel des Autors hat das zu sortierende Array eher sequentielle numerische Indizes als String-Indizes, also usort besser geeignet ist. Verwendung von uasort auf ein sequentiell indiziertes Array führt zu einem sortierten Array, das nicht nach seinen numerischen Indizes geordnet ist, so dass das erste Element in einer foreach Schleife ist nicht $your_array[0] was wohl kaum ein wünschenswertes Verhalten ist.

163voto

Mariano Iglesias Punkte 1697

Während andere zu Recht die Verwendung von array_multisort() aus irgendeinem Grund scheint keine Antwort die Existenz von array_column() was die Lösung erheblich vereinfachen kann. Mein Vorschlag wäre also:

array_multisort(array_column($inventory, 'price'), SORT_DESC, $inventory);

Wenn Sie wollen Sortierung ohne Berücksichtigung der Groß-/Kleinschreibung auf Zeichenketten, können Sie SORT_NATURAL|SORT_FLAG_CASE

array_multisort(array_column($inventory, 'key_name'), SORT_DESC, SORT_NATURAL|SORT_FLAG_CASE, $inventory);

3 Stimmen

Aus irgendeinem Grund war ich nicht in der Lage, es mit Zeichenketten mit Klein-/Großbuchstaben funktionieren zu lassen. Selbst mit der SORT_FLAG_CASE. Das folgende funktionierte für String-Vergleich für mich: array_multisort( array_map(strtolower, array_column($ipr_projects, 'Name')), SORT_ASC, $ipr_projects);

0 Stimmen

Funktioniert gut PHP 7.4

46voto

zombat Punkte 89911

Da Ihre Array-Elemente selbst Arrays mit String-Schlüsseln sind, ist es am besten, eine eigene Vergleichsfunktion zu definieren. Das ist ziemlich schnell und einfach zu machen. Versuchen Sie dies:

function invenDescSort($item1,$item2)
{
    if ($item1['price'] == $item2['price']) return 0;
    return ($item1['price'] < $item2['price']) ? 1 : -1;
}
usort($inventory,'invenDescSort');
print_r($inventory);

Erzeugt das Folgende:

Array
(
    [0] => Array
        (
            [type] => pork
            [price] => 5.43
        )

    [1] => Array
        (
            [type] => fruit
            [price] => 3.5
        )

    [2] => Array
        (
            [type] => milk
            [price] => 2.9
        )

)

4 Stimmen

Kombiniert mit einigen der anderen Kommentare hier (uasort und anonyme Inline-Funktionen), erhalten Sie diesen Einzeiler: uasort( $inventory, function ($a, $b) { if ( $a==$b ) return 0; else return ($a > $b) ? -1 : 1; });

0 Stimmen

@AlanPorter usort scheint angemessener zu sein als uasort zum Sortieren eines Arrays mit aufeinanderfolgenden numerischen Schlüsseln. Das Ergebnis ist ein Array, bei dem das erste Element den Index 1 und das zweite Element hat den Index 0 ist ein seltsames Verhalten und eine sichere Falle für Leute, die mit den Details von PHPs Arrays nicht vertraut sind; usort gibt das Ergebnis, das man intuitiv erwartet.

30voto

Danielzt Punkte 453

Ich habe damit abgeschlossen:

function sort_array_of_array(&$array, $subfield)
{
    $sortarray = array();
    foreach ($array as $key => $row)
    {
        $sortarray[$key] = $row[$subfield];
    }

    array_multisort($sortarray, SORT_ASC, $array);
}

Rufen Sie einfach die Funktion auf und übergeben Sie das Array und den Namen des Feldes des Arrays der zweiten Ebene. Zum Beispiel:

sort_array_of_array($inventory, 'price');

2 Stimmen

@MarkAmery Ich bevorzuge Antworten, die in Funktionen enthalten sind. Es ermutigt Copy-Pasteure, Funktionen zu verwenden und hoffentlich weniger Spaghetti-Code zu schreiben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X