Urutkan array objek berdasarkan bidang objek

514

Bagaimana saya bisa mengurutkan array objek ini dengan salah satu bidangnya, suka nameatau 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
sumber

Jawaban:

699

Gunakan usort , inilah contoh yang diadaptasi dari manual:

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

usort($your_data, "cmp");

Anda juga dapat menggunakan callable apa pun sebagai argumen kedua. Berikut ini beberapa contohnya:

  • Menggunakan fungsi anonim (dari PHP 5.3)

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

    usort($your_data, array($this, "cmp")); // "cmp" should be a method in the class
  • Menggunakan fungsi panah (dari PHP 7.4)

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

Juga, jika Anda membandingkan nilai numerik, fn($a, $b) => $a->count - $b->countsebagai fungsi "bandingkan" harus melakukan trik.

cambraca
sumber
93
Ini bagus, tetapi jika fungsi penyortiran berada di kelas yang sama dengan fungsi pemanggilan, Anda harus menggunakan: usort ($ your_data, array ($ this, "cmp"));
rmooney
7
@ rmooney Ya, tetapi hanya jika Anda berada di dalam kelas.
cambraca
11
berikan komentar pertama oleh @rmooney dalam jawaban Anda
Mohammad Faisal
7
Atau jika fungsi perbandingan Anda ada dalam model / objek yang Anda bandingkan (yang merupakan desain yang lebih bersih menurut saya), Anda harus memasukkan namespace lengkap ke model / objek Anda seperti ini: uasort ($ members, array ("Path \ to \ your \ Model \ Member "," compareByName "));
clauziere
3
ini tidak mengembalikan apa-apa kepada saya diurutkan, hanya yang paling besar pertama, dan semua sisanya saya membatalkan
Alberto Acuña
472

Inilah cara yang lebih baik menggunakan penutupan

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

Harap dicatat ini tidak ada dalam dokumentasi PHP tetapi jika Anda menggunakan penutupan 5.3+ didukung di mana argumen yang bisa dipanggil dapat diberikan.

Scott Quinlan
sumber
16
Saya suka yang ini lebih baik daripada jawaban yang diterima karena kita dapat dengan cepat mendefinisikan fungsi bandingkan dan dapat digunakan di kelas
Nam G VU
11
Jika Anda ingin mempertahankan kunci array gunakanuasort()
gillytech
10
Untuk semacam desc,-1 * strcmp($a->name, $b->name);
Wallace Maxters
17
Tidak perlu mengalikan untuk mengurutkan desc. Tukar saja args:strcmp($b->name, $a->name)
zxcat
3
Anda mungkin menghadapi situasi, seperti saya, di mana jawaban yang diterima lebih disukai daripada yang ini. Misalnya, Anda mungkin memiliki orang tua dan kelas anak. Kelas anak menimpa fungsi yang menggunakan usorttetapi fungsi perbandingannya sama. Dengan menggunakan ini Anda harus menduplikasi kode untuk penutupan daripada melakukan panggilan ke protected staticmetode yang Anda perlu mendefinisikan hanya sekali di kelas induk.
Pere
48

Jika Anda ingin mengurutkan nilai integer:

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

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

DIPERBARUI dengan string, jangan lupa untuk mengonversi ke register yang sama (atas atau bawah)

// 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
sumber
44

jika Anda menggunakan php oop, Anda mungkin perlu mengubah ke:

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
sumber
28
usort($array, 'my_sort_function');

var_dump($array);

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

Kode yang sama akan dengan countbidang.

Lebih detail tentang usort: http://ru2.php.net/usort

Btw, dari mana Anda mendapatkan array itu? Saya harap itu bukan dari database?

zerkms
sumber
1
Sebenarnya $resultakan berisi TRUEjika berhasil, dan perbandingan Anda seharusnya $a->name > $b->name. :)
cambraca
2
@cambraca: oh, lupa menerima array dengan referensi. Btw, OP tidak mengatakan pesanan mana yang dia butuhkan untuk mengurutkan koleksi.
zerkms
1
baik ya, itu adalah database :) sebenarnya dari fungsi yang mendapatkan data dari database
Alex
3
@ Alex: mengapa Anda tidak mengurutkannya dalam database? ORDER BY count
zerkms
1
ini lebih rumit, karena itu adalah bagian fungsi stadard dari wordpress, dan ketika saya sedang menulis sebuah plugin, saya tidak dapat mengubah file wp. Saya mencoba contoh Anda menggunakan create_function (karena saya menggunakannya di dalam kelas dan saya tidak tahu cara meneruskan nama fungsi ke usort): create_function('$a,$b', "return $a->count < $b->count;")tapi saya tidak bisa membuatnya bekerja :( Saya mendapatkan beberapa pemberitahuan dan memperingatkan bahwa usort mengharapkan parameter 2 menjadi panggilan balik yang valid
Alex
9

Anda dapat menggunakan fungsi ini (berfungsi dalam Versi PHP> = 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;

        });
    }
}

Contoh:

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
sumber
Saya menggunakan $a->{$key}dan $b->{$key}bukannya $a[$key]dan $b[$key]seperti kita, sebenarnya, berurusan dengan properti daripada anggota array, tapi ini masih jawaban yang saya cari.
SteJ
Silakan terapkan saran @ SteJ dalam kode contoh sebagai solusi yang Anda berikan hanya berfungsi untuk objek sederhana tetapi dengan perbaikan SteJ berfungsi untuk semua array objek yang telah saya coba
user2993145
6

Anda dapat menggunakan usort, seperti ini:

usort($array,function($first,$second){
    return strcmp($first->name, $second->name);
});
Luca C.
sumber
5

Jika semuanya gagal di sini adalah solusi lain:

$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.
sumber
Anda harus mendapatkan Oscar untuk solusi ini! ))))) Terima kasih
Imeksbank
4

Kelemahan dari semua jawaban di sini adalah bahwa mereka menggunakan nama bidang statis , jadi saya menulis versi yang disesuaikan dalam gaya OOP. Diasumsikan Anda menggunakan metode pengambil Anda bisa langsung menggunakan Kelas ini dan menggunakan nama bidang sebagai parameter . Mungkin seseorang menganggapnya berguna.

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;
    }
} 
aduh
sumber
3

jika Anda ingin mengurutkan tanggal

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

Alternatif sederhana yang memungkinkan Anda menentukan secara dinamis bidang tempat penyortiran didasarkan:

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

Ini didasarkan pada kelas Penutupan , yang memungkinkan fungsi anonim. Ini tersedia sejak PHP 5.3.

clami219
sumber
2

Jika Anda membutuhkan lokal perbandingan string berdasarkan, Anda dapat menggunakan strcollbukan strcmp.

Ingat untuk pertama kali menggunakan setlocaledengan LC_COLLATEmengatur informasi lokal jika diperlukan.

  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
sumber
2

Jika Anda menggunakan ini di dalam Codeigniter, Anda dapat menggunakan metode:

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

@ rmooney terima kasih atas sarannya. Ini sangat membantu saya.

Pengembang PHP
sumber
Bagaimana tepatnya Codeigniter ini spesifik?
ggdx
2

Terima kasih atas inspirasinya, saya juga harus menambahkan parameter $ translator eksternal

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

Jika Anda perlu mengurutkan berdasarkan satu bidang, maka itu usortadalah pilihan yang baik. Namun, solusinya dengan cepat menjadi berantakan jika Anda perlu mengurutkan berdasarkan beberapa bidang. Dalam hal ini, pustaka YaLinqo * dapat digunakan, yang mengimplementasikan sintaks query seperti SQL untuk array dan objek. Ini memiliki sintaks yang bagus untuk semua kasus:

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

Di sini, '$v->count'adalah singkatan untuk function ($v) { return $v->count; }(keduanya dapat digunakan). Rantai metode ini mengembalikan iterator, tetapi Anda bisa mendapatkan array dengan menambahkan ->toArray()pada akhirnya jika Anda membutuhkannya.

* Dikembangkan oleh saya

Athari
sumber
1

Anda dapat menggunakan fungsi yang diurutkan dari Nspl :

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
sumber
Tolong jelaskan mengapa OP akan membutuhkan seluruh perpustakaan tambahan untuk menyediakan fasilitas yang tampaknya diselesaikan dengan fungsi
bawaan
1

Inilah yang saya miliki untuk kelas utilitas

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

Sebut saja:

Util::sortArrayByName($array, "array_property_name");
Demodave
sumber
1

Anda dapat menggunakan usort seperti ini

Jika Anda ingin mengurutkan berdasarkan nomor:

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

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

usort($a, "cmp");

Atau 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");

Lihat lebih lanjut: https://www.php.net/manual/en/function.usort.php

Alex
sumber