Sắp xếp mảng các đối tượng theo các trường đối tượng


514

Làm thế nào tôi có thể sắp xếp mảng các đối tượng này theo một trong các trường của nó, như namehoặc 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
        )

   ....

Câu trả lời:


699

Sử dụng usort , đây là một ví dụ được điều chỉnh từ hướng dẫn:

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

usort($your_data, "cmp");

Bạn cũng có thể sử dụng bất kỳ cuộc gọi nào làm đối số thứ hai. Dưới đây là một số ví dụ:

  • Sử dụng các hàm ẩn danh (từ PHP 5.3)

    usort($your_data, function($a, $b) {return strcmp($a->name, $b->name);});
  • Từ trong một lớp học

    usort($your_data, array($this, "cmp")); // "cmp" should be a method in the class
  • Sử dụng các hàm mũi tên (từ PHP 7.4)

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

Ngoài ra, nếu bạn đang so sánh các giá trị số, fn($a, $b) => $a->count - $b->countvì hàm "so sánh" sẽ thực hiện thủ thuật.


93
Điều này thật tuyệt, nhưng nếu hàm sắp xếp nằm trong cùng lớp với hàm gọi, bạn nên sử dụng: usort ($ your_data, mảng ($ this, "cmp"));
rmooney

7
@rmooney Có, nhưng chỉ khi bạn ở trong một lớp.
cambraca

11
đưa bình luận đầu tiên của @rmooney vào câu trả lời của bạn
Mohammad Faisal

7
Hoặc nếu chức năng so sánh của bạn nằm trong mô hình / đối tượng mà bạn đang so sánh (theo ý kiến ​​của tôi là thiết kế sạch hơn), bạn phải bao gồm không gian tên đầy đủ cho mô hình / đối tượng của mình như sau: uasort ($ thành viên, mảng ("Đường dẫn \ đến \ your \ Model \ Member "," soByName "));
clauziere

3
điều này không trả lại cho tôi bất cứ thứ gì được sắp xếp, chỉ là cái lớn nhất đầu tiên, và tất cả phần còn lại tôi không sắp xếp
Alberto Acuña

472

Đây là một cách tốt hơn bằng cách sử dụng đóng cửa

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

Xin lưu ý rằng đây không phải là tài liệu của PHP nhưng nếu bạn sử dụng 5,3+ lần đóng được hỗ trợ thì có thể cung cấp các đối số có thể gọi được.


16
Tôi thích câu trả lời này tốt hơn câu trả lời được chấp nhận vì chúng tôi có thể nhanh chóng xác định chức năng so sánh và có thể sử dụng trong một lớp
Nam G VU

11
Nếu bạn muốn duy trì các khóa mảng, hãy sử dụnguasort()
gillytech

10
Để sắp xếp desc,-1 * strcmp($a->name, $b->name);
Wallace Maxters 14/07/2015

17
Không cần phải nhân lên để sắp xếp desc. Chỉ cần trao đổi lập luận:strcmp($b->name, $a->name)
zxcat

3
Bạn có thể gặp một tình huống, như tôi, trong đó câu trả lời được chấp nhận là thích hợp hơn với câu hỏi này. Ví dụ, bạn có thể có một lớp cha mẹ và một lớp con. Lớp con ghi đè một hàm sử dụng usortnhưng hàm so sánh là như nhau. Sử dụng điều này, bạn cần sao chép mã cho bao đóng thay vì thực hiện cuộc gọi đến một protected staticphương thức mà bạn chỉ cần xác định một lần trong lớp cha.
Pere

48

Nếu bạn muốn sắp xếp các giá trị nguyên:

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

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

CẬP NHẬT với chuỗi đừng quên chuyển đổi sang cùng một thanh ghi (trên hoặc dưới)

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

nếu bạn đang sử dụng php oop, bạn có thể cần phải đổi thành:

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;
}

Các mã tương tự sẽ được với các countlĩnh vực.

Thêm chi tiết về usort: http://ru2.php.net/usort

Btw, bạn đã lấy mảng đó từ đâu? Tôi hy vọng rằng không phải từ cơ sở dữ liệu?


1
Thực tế $resultsẽ chứa TRUEnếu nó thành công, và so sánh của bạn nên được $a->name > $b->name. :)
cambraca

2
@cambraca: oh, quên nó chấp nhận mảng bằng cách tham khảo. Btw, OP không cho biết anh ta cần sắp xếp bộ sưu tập nào.
zerkms

1
vâng, đó là một cơ sở dữ liệu :) thực sự từ một chức năng lấy dữ liệu từ cơ sở dữ liệu
Alex

3
@Alex: tại sao bạn không sắp xếp nó trong cơ sở dữ liệu? ORDER BY count
zerkms

1
nó phức tạp hơn, bởi vì đó là một phần chức năng hoàn hảo của wordpress và khi tôi đang viết một plugin, tôi không thể thay đổi các tệp wp. Tôi đã thử ví dụ của bạn bằng cách sử dụng create_function (vì tôi đang sử dụng nó trong một lớp và tôi không biết làm thế nào để chuyển tên hàm cho usort): create_function('$a,$b', "return $a->count < $b->count;")nhưng tôi không thể làm cho nó hoạt động :( Tôi nhận được một vài thông báo và cảnh báo rằng usort hy vọng tham số 2 sẽ là một cuộc gọi lại hợp lệ
Alex

9

Bạn có thể sử dụng chức năng này (hoạt động trong Phiên bản 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;

        });
    }
}

Thí dụ:

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)

Tôi đã sử dụng $a->{$key}$b->{$key}thay vì $a[$key]$b[$key]như chúng ta, nói đúng ra, xử lý các thuộc tính hơn là các thành viên mảng, nhưng đây vẫn là câu trả lời tôi đang tìm kiếm.
SteJ

Vui lòng triển khai đề xuất của @ SteJ trong mã ví dụ như giải pháp bạn đưa ra chỉ hoạt động cho các đối tượng đơn giản nhưng với sửa lỗi của SteJ, nó hoạt động cho tất cả các mảng đối tượng tôi đã thử trên
user2993145

6

Bạn có thể sử dụng usort, như thế này:

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

5

Nếu mọi thứ thất bại ở đây là một giải pháp khác:

$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;

Bạn sẽ nhận được một giải Oscar cho giải pháp này! ))))) Thankyou
Imeksbank

4

Nhược điểm của tất cả các câu trả lời ở đây là chúng sử dụng tên trường tĩnh , vì vậy tôi đã viết một phiên bản điều chỉnh theo kiểu OOP. Giả sử bạn đang sử dụng các phương thức getter, bạn có thể trực tiếp sử dụng Lớp này và sử dụng tên trường làm tham số . Có lẽ ai đó thấy nó hữu ích.

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

nếu bạn muốn sắp xếp ngày

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

3

Một thay thế đơn giản cho phép bạn xác định động trường mà phân loại dựa trên:

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

Điều này dựa trên lớp Đóng , cho phép các hàm ẩn danh. Nó có sẵn kể từ PHP 5.3.


2

Nếu bạn cần so sánh chuỗi dựa trên cục bộ, bạn có thể sử dụng strcollthay vì strcmp.

Lưu ý sử dụng đầu tiên setlocalevới LC_COLLATEđể đặt thông tin ngôn ngữ nếu cần.

  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

Nếu bạn đang sử dụng cái này bên trong Codeigniter, bạn có thể sử dụng các phương thức:

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

@rmooney cảm ơn bạn đã gợi ý. Nó thực sự giúp tôi.


Làm thế nào chính xác là Codeigniter cụ thể?
ggdx

2

Cảm ơn những nguồn cảm hứng, tôi cũng đã phải thêm một tham số $ translator bên ngoài

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

1

Nếu bạn chỉ cần sắp xếp theo một lĩnh vực, thì đó usortlà một lựa chọn tốt. Tuy nhiên, giải pháp nhanh chóng trở nên lộn xộn nếu bạn cần sắp xếp theo nhiều trường. Trong trường hợp này, thư viện YaLinqo * có thể được sử dụng, thực hiện cú pháp truy vấn giống như SQL cho các mảng và đối tượng. Nó có một cú pháp đẹp cho tất cả các trường hợp:

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

Ở đây, '$v->count'là một tốc ký cho function ($v) { return $v->count; }(hoặc có thể được sử dụng). Các chuỗi phương thức này trả về các trình vòng lặp, nhưng bạn có thể nhận được các mảng bằng cách thêm ->toArray()vào cuối nếu bạn cần nó.

* được phát triển bởi tôi


1

Bạn có thể sử dụng chức năng được sắp xếp từ 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'));

Vui lòng giải thích lý do tại sao OP sẽ cần cả một thư viện bổ sung để cung cấp một cơ sở dường như được giải quyết bằng các chức năng được xây dựng
ggdx

1

Đây là những gì tôi có cho một lớp tiện ích

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

Gọi nó đi:

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

1

Bạn có thể sử dụng usort như thế này

Nếu bạn muốn sắp xếp theo số:

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

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

usort($a, "cmp");

Hoặc 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");

Xem thêm: https://www.php.net/manual/en/feft.usort.php

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.