Sortieren Sie das Array von Objekten nach Objektfeldern


514

Wie kann ich dieses Array von Objekten nach einem seiner Felder sortieren, wie nameoder count?

  Array
(
    [0] => stdClass Object
        (
            [ID] => 1
            [name] => Mary Jane
            [count] => 420
        )

    [1] => stdClass Object
        (
            [ID] => 2
            [name] => Johnny
            [count] => 234
        )

    [2] => stdClass Object
        (
            [ID] => 3
            [name] => Kathy
            [count] => 4354
        )

   ....

Antworten:


699

Verwenden Sie usort . Hier ist ein Beispiel aus dem Handbuch:

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

usort($your_data, "cmp");

Sie können auch jedes aufrufbare als zweites Argument verwenden. Hier sind einige Beispiele:

  • Verwendung anonymer Funktionen (ab PHP 5.3)

    usort($your_data, function($a, $b) {return strcmp($a->name, $b->name);});
  • Aus einer Klasse heraus

    usort($your_data, array($this, "cmp")); // "cmp" should be a method in the class
  • Verwenden von Pfeilfunktionen (ab PHP 7.4)

    usort($your_data, fn($a, $b) => strcmp($a->name, $b->name));

Wenn Sie numerische Werte fn($a, $b) => $a->count - $b->countvergleichen, sollte die Funktion "Vergleichen" den Trick ausführen.


93
Das ist großartig, aber wenn sich die Sortierfunktion in derselben Klasse wie die aufrufende Funktion befindet, sollten Sie Folgendes verwenden: usort ($ your_data, array ($ this, "cmp"));
Rmooney

7
@rmooney Ja, aber nur, wenn Sie in einer Klasse sind.
Cambraca


7
Oder wenn sich Ihre Vergleichsfunktion in Ihrem Modell / Objekt befindet, das Sie vergleichen (was meiner Meinung nach ein saubereres Design ist), müssen Sie den vollständigen Namespace wie folgt in Ihr Modell / Objekt einfügen: uasort ($ members, array ("Path \ to \ your \ Model \ Member "," compareByName "));
Clauziere

3
Dies gibt mir nichts sortiertes zurück, nur das größte zuerst, und alles andere, was ich unsortiere
Alberto Acuña

472

Hier ist eine schönere Art, Verschlüsse zu verwenden

usort($your_data, function($a, $b)
{
    return strcmp($a->name, $b->name);
});

Bitte beachten Sie, dass dies nicht in der PHP-Dokumentation enthalten ist. Wenn Sie jedoch 5.3+ Schließungen verwenden, werden diese unterstützt, wenn aufrufbare Argumente angegeben werden können.


16
Ich liebe diese Antwort besser als die akzeptierte Antwort, da wir die Vergleichsfunktion schnell definieren und in einer Klasse verwenden können
Nam G VU

11
Wenn Sie die Array-Schlüssel erhalten möchten, verwenden Sieuasort()
gillytech

10
Für sort desc,-1 * strcmp($a->name, $b->name);
Wallace Maxters

17
Keine Notwendigkeit zu multiplizieren, um desc zu sortieren. Tauschen Sie einfach die strcmp($b->name, $a->name)
Argumente aus

3
Möglicherweise stoßen Sie auf eine Situation wie mich, in der die akzeptierte Antwort dieser vorzuziehen ist. Beispielsweise können Sie eine Eltern- und eine Kinderklasse haben. Die untergeordnete Klasse überschreibt eine Funktion, die verwendet wird, usortaber die Vergleichsfunktion ist dieselbe. Wenn Sie dies verwenden, müssen Sie den Code für den Abschluss duplizieren, anstatt eine protected staticMethode aufzurufen, die Sie nur einmal in der übergeordneten Klasse definieren müssten.
Pere

48

Wenn Sie ganzzahlige Werte sortieren möchten:

// Desc sort
usort($array,function($first,$second){
    return $first->number < $second->number;
});

// Asc sort
usort($array,function($first,$second){
    return $first->number > $second->number;
});

AKTUALISIERT mit der Zeichenfolge Vergessen Sie nicht, in dasselbe Register (oberes oder unteres) zu konvertieren.

// Desc sort
usort($array,function($first,$second){
    return strtolower($first->text) < strtolower($second->text);
});

// Asc sort
usort($array,function($first,$second){
    return strtolower($first->text) > strtolower($second->text);
});

44

Wenn Sie PHPOOP verwenden, müssen Sie möglicherweise Folgendes ändern:

public static function cmp($a, $b) 
{
    return strcmp($a->name, $b->name);
}

//in this case FUNCTION_NAME would be cmp
usort($your_data, array('YOUR_CLASS_NAME','FUNCTION_NAME')); 

28
usort($array, 'my_sort_function');

var_dump($array);

function my_sort_function($a, $b)
{
    return $a->name < $b->name;
}

Der gleiche Code wird mit dem countFeld sein.

Weitere Details zu usort: http://ru2.php.net/usort

Übrigens, woher hast du das Array? Ich hoffe das nicht aus der Datenbank?


1
Eigentlich $resultwird enthalten, TRUEwenn es erfolgreich ist, und Ihr Vergleich sollte sein $a->name > $b->name. :)
Cambraca

2
@ Cambraca: Oh, vergessen, es akzeptiert Array als Referenz. Übrigens hat OP nicht gesagt, in welcher Reihenfolge er die Sammlung sortieren muss.
Zerkms

1
Nun ja, es ist eine Datenbank :) Eigentlich von einer Funktion, die die Daten aus der Datenbank erhält
Alex

3
@Alex: warum sortierst du es dann nicht in der Datenbank? ORDER BY count
Zerkms

1
Es ist komplizierter, weil dies ein Standardfunktionsteil von WordPress ist und ich beim Schreiben eines Plugins keine WP-Dateien ändern kann. Ich habe Ihr Beispiel mit create_function ausprobiert (weil ich es in einer Klasse verwende und nicht weiß, wie ich den Funktionsnamen an usort übergeben soll): create_function('$a,$b', "return $a->count < $b->count;")aber ich kann es nicht zum Laufen bringen :( Ich bekomme ein paar Hinweise und warne davor usort erwartet, dass Parameter 2 ein gültiger Rückruf ist
Alex

9

Sie können diese Funktion verwenden (funktioniert in PHP Version> = 5.3):

function sortArrayByKey(&$array,$key,$string = false,$asc = true){
    if($string){
        usort($array,function ($a, $b) use(&$key,&$asc)
        {
            if($asc)    return strcmp(strtolower($a{$key}), strtolower($b{$key}));
            else        return strcmp(strtolower($b{$key}), strtolower($a{$key}));
        });
    }else{
        usort($array,function ($a, $b) use(&$key,&$asc)
        {
            if($a[$key] == $b{$key}){return 0;}
            if($asc) return ($a{$key} < $b{$key}) ? -1 : 1;
            else     return ($a{$key} > $b{$key}) ? -1 : 1;

        });
    }
}

Beispiel:

sortArrayByKey($yourArray,"name",true); //String sort (ascending order)
sortArrayByKey($yourArray,"name",true,false); //String sort (descending order)
sortArrayByKey($yourArray,"id"); //number sort (ascending order)
sortArrayByKey($yourArray,"count",false,false); //number sort (descending order)

Ich habe $a->{$key}und $b->{$key}eher als $a[$key]und $b[$key]wie wir es tun, streng genommen eher mit Eigenschaften als mit Array-Mitgliedern zu tun, aber dies war immer noch die Antwort, nach der ich gesucht habe.
SteJ

Bitte implementieren Sie den Vorschlag von @ SteJ in den Beispielcode, da die von Ihnen angegebene Lösung nur für einfache Objekte funktioniert, aber mit SteJs Fix für alle Arrays von Objekten funktioniert, auf denen ich es ausprobiert habe
user2993145

6

Sie können usortwie folgt verwenden:

usort($array,function($first,$second){
    return strcmp($first->name, $second->name);
});

5

Wenn hier alles fehlschlägt, gibt es eine andere Lösung:

$names = array(); 
foreach ($my_array as $my_object) {
    $names[] = $my_object->name; //any object field
}

array_multisort($names, SORT_ASC, $my_array);

return $my_array;

Sie sollten einen Oscar für diese Lösung bekommen! ))))) Danke
Imeksbank

4

Der Nachteil aller Antworten hier ist, dass sie statische Feldnamen verwenden, daher habe ich eine angepasste Version im OOP-Stil geschrieben. Angenommen, Sie verwenden Getter-Methoden, könnten Sie diese Klasse direkt verwenden und den Feldnamen als Parameter verwenden . Wahrscheinlich findet es jemand nützlich.

class CustomSort{

    public $field = '';

    public function cmp($a, $b)
    {
        /**
         * field for order is in a class variable $field
         * using getter function with naming convention getVariable() we set first letter to uppercase
         * we use variable variable names - $a->{'varName'} would directly access a field
         */
        return strcmp($a->{'get'.ucfirst($this->field)}(), $b->{'get'.ucfirst($this->field)}());
    }

    public function sortObjectArrayByField($array, $field)
    {
        $this->field = $field;
        usort($array, array("Your\Namespace\CustomSort", "cmp"));;
        return $array;
    }
} 

3

wenn Sie Daten sortieren möchten

   usort($threads,function($first,$second){
        return strtotime($first->dateandtime) < strtotime($second->dateandtime);
    });

3

Eine einfache Alternative, mit der Sie das Feld, auf dem die Sortierung basiert, dynamisch bestimmen können:

$order_by = 'name';
usort($your_data, function ($a, $b) use ($order_by)
{
    return strcmp($a->{$order_by}, $b->{$order_by});
});

Dies basiert auf der Closure-Klasse , die anonyme Funktionen zulässt. Es ist seit PHP 5.3 verfügbar.


2

Wenn Sie einen lokal basierten Zeichenfolgenvergleich benötigen, können Sie strcollanstelle von verwenden strcmp.

Denken Sie daran , dem ersten Gebrauch setlocalemit LC_COLLATEzu Satz locale Informationen , wenn nötig.

  usort($your_data,function($a,$b){
    setlocale (LC_COLLATE, 'pl_PL.UTF-8'); // Example of Polish language collation
    return strcoll($a->name,$b->name);
  });

2

Wenn Sie dies in Codeigniter verwenden, können Sie die folgenden Methoden verwenden:

usort($jobs, array($this->job_model, "sortJobs"));  // function inside Model
usort($jobs, array($this, "sortJobs")); // Written inside Controller.

@rmooney danke für den Vorschlag. Es hilft mir wirklich.


Wie genau ist dieser Codeigniter spezifisch?
ggdx

2

Vielen Dank für die Inspirationen, ich musste auch einen externen $ translator-Parameter hinzufügen

usort($listable_products, function($a, $b) {
    global $translator;
    return strcmp($a->getFullTitle($translator), $b->getFullTitle($translator));
});

1

Wenn Sie nur nach einem Feld sortieren müssen, usortist dies eine gute Wahl. Die Lösung wird jedoch schnell unübersichtlich, wenn Sie nach mehreren Feldern sortieren müssen. In diesem Fall kann die YaLinqo- Bibliothek * verwendet werden, die eine SQL-ähnliche Abfragesyntax für Arrays und Objekte implementiert. Es hat eine hübsche Syntax für alle Fälle:

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

Hier '$v->count'ist eine Abkürzung für function ($v) { return $v->count; }(entweder kann verwendet werden). Diese Methodenketten geben Iteratoren zurück, aber Sie können Arrays erhalten, indem Sie sie ->toArray()am Ende hinzufügen, wenn Sie sie benötigen.

* von mir entwickelt


1

Sie können die sortierte Funktion von Nspl verwenden :

use function \nspl\a\sorted;
use function \nspl\op\propertyGetter;
use function \nspl\op\methodCaller;

// Sort by property value
$sortedByCount = sorted($objects, propertyGetter('count'));

// Or sort by result of method call
$sortedByName = sorted($objects, methodCaller('getName'));

Bitte erläutern Sie, warum das OP eine ganze zusätzliche Bibliothek benötigt, um eine Einrichtung bereitzustellen, die scheinbar durch eingebaute Funktionen aufgelöst wird
ggdx

1

Das habe ich für eine Utility-Klasse

class Util
{
    public static function sortArrayByName(&$arrayToSort, $meta) {
        usort($arrayToSort, function($a, $b) use ($meta) {
            return strcmp($a[$meta], $b[$meta]);
        });
    }
}

Nennen:

Util::sortArrayByName($array, "array_property_name");

1

Sie können usort so verwenden

Wenn Sie nach Nummern sortieren möchten:

function cmp($a, $b)
{
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

$a = array(3, 2, 5, 6, 1);

usort($a, "cmp");

Oder Abc char:

function cmp($a, $b)
{
    return strcmp($a["fruit"], $b["fruit"]);
}

$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";

usort($fruits, "cmp");

Weitere Informationen: https://www.php.net/manual/en/function.usort.php

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.