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
        )

   ....
Alex
quelle

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.

Cambraca
quelle
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
11
Setzen Sie den ersten Kommentar von @rmooney in Ihre Antwort
Mohammad Faisal
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.

Scott Quinlan
quelle
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);
});
Roman Yakoviv
quelle
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')); 
Doron Segal
quelle
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?

zerkms
quelle
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)
PoengAlex
quelle
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);
});
Luca C.
quelle
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;
Adrian P.
quelle
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;
    }
} 
oshell
quelle
3

wenn Sie Daten sortieren möchten

   usort($threads,function($first,$second){
        return strtotime($first->dateandtime) < strtotime($second->dateandtime);
    });
Nicolas Giszpenc
quelle
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.

clami219
quelle
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);
  });
Wilq
quelle
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.

Php Entwickler
quelle
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));
});
michalzuber
quelle
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

Athari
quelle
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'));
Ihor Burlachenko
quelle
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");
Demodave
quelle
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

Alex
quelle