按对象字段对对象数组进行排序


514

如何按其字段之一(例如name或)对对象数组进行排序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
        )

   ....

Answers:


698

使用usort,这是从手册改编而成的示例:

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

usort($your_data, "cmp");

您还可以将任何callable用作第二个参数。这里有些例子:

  • 使用匿名函数(来自PHP 5.3)

    usort($your_data, function($a, $b) {return strcmp($a->name, $b->name);});
  • 从班级内部

    usort($your_data, array($this, "cmp")); // "cmp" should be a method in the class
  • 使用箭头函数(来自PHP 7.4)

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

另外,如果要比较数字值,fn($a, $b) => $a->count - $b->count则应使用“比较”功能。


93
这很好,但是如果排序函数与调用函数在同一类中,则应使用:usort($ your_data,array($ this,“ cmp”));
rmooney13年

7
@rmooney是的,但仅当您在课堂上时。
cambraca

11
在您的回答中添加@rmooney第一条评论
Mohammad Faisal

7
或者,如果您的比较函数在要比较的模型/对象中(我认为这是一种更简洁的设计),则必须像这样将完整的命名空间包括到模型/对象中:uasort($ members,array(“ Path \ to \ your \ Model \ Member“,” compareByName“));
clauziere 2014年

3
这回不要我什么排序,只是最大的第一,和所有其余的我不排序
阿尔贝托·阿库尼亚

472

这是使用闭包的更好方法

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

请注意,这不在PHP文档中,但是如果您使用5.3+闭包,则可以在其中提供可调用参数。


16
我比接受的答案更喜欢这个答案,因为我们可以快速定义比较函数并可以在一个类中使用
Nam G VU 2012年

11
如果要保留阵列键,请使用uasort()
gillytech

10
对于排序说明,-1 * strcmp($a->name, $b->name);
华莱士·麦克斯特斯

17
无需乘以排序desc。只需交换参数:strcmp($b->name, $a->name)
zxcat

3
您可能会遇到像我这样的情况,在这种情况下,可接受的答案比该答案更可取。例如,您可能有一个父类和一个子类。子类将覆盖使用的功能,usort但比较功能相同。使用此方法,您需要复制闭包的代码,而不是对protected static方法的调用,您只需在父类中定义一次即可。
佩雷

48

如果要对整数值进行排序:

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

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

用字符串更新不要忘了转换为相同的寄存器(高位或低位)

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

如果您使用的是php oop,则可能需要更改为:

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

count字段将使用相同的代码。

有关的更多详细信息usorthttp : //ru2.php.net/usort

顺便说一句,您是从哪里获得该阵列的?我希望不是从数据库?


1
如果成功,实际上$result将包含TRUE,您的比较应该为$a->name > $b->name。:)
cambraca

2
@cambraca:哦,忘了它接受引用数组。顺便说一句,OP没有说他需要对收集进行排序的顺序。
zerkms 2010年

1
好吧,是的,这是一个数据库:)实际上是从一个从数据库中获取数据的函数中实现的
Alex 2010年

3
@Alex:为什么不对数据库进行排序?ORDER BY count
zerkms 2010年

1
它更复杂,因为这是wordpress的标准功能部分,并且在编写插件时,无法更改wp文件。我使用create_function尝试了您的示例(因为我正在类中使用它,并且我不知道如何将函数名传递给usort):create_function('$a,$b', "return $a->count < $b->count;")但是我无法使其工作:(我收到一些通知并警告说usort期望参数2是有效的回调
Alex 2010年

9

您可以使用此功能(在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;

        });
    }
}

例:

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)

我用$a->{$key}$b->{$key},而不是$a[$key]$b[$key],因为我们是严格来说,处理性能,而不是阵列成员,但是这仍然是我一直在寻找的答案。
SteJ

请在示例代码中实现@SteJ的建议,因为您提供的解决方案仅适用于简单对象,但通过SteJ的修复,它适用于我尝试过的所有对象数组
user2993145

6

您可以这样使用usort

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

5

如果一切失败,这是另一种解决方案:

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

您应该为此解决方案获得奥斯卡奖!)))))谢谢
-Imeksbank,

4

这里所有答案的缺点是它们使用静态字段名称,因此我以OOP风格编写了调整后的版本。假设您使用的是getter方法,则可以直接使用此类,并将字段名称用作参数。可能有人觉得它有用。

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

一个简单的替代方法,使您可以动态确定排序所基于的字段:

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

这基于Closure类该类允许匿名函数。自PHP 5.3起可用。


2

如果您需要基于本地的字符串比较,则可以使用strcoll代替strcmp

如果需要,请记住首先使用setlocalewith LC_COLLATE来设置区域信息。

  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

如果在Codeigniter中使用此方法,则可以使用以下方法:

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

@rmooney谢谢您的建议。真的对我有帮助。


此Codeigniter具体如何?
ggdx

2

感谢您的启发,我还必须添加一个外部$ translator参数

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

1

如果您只需要按一个字段排序,那usort是一个不错的选择。但是,如果您需要按多个字段进行排序,则解决方案很快就会变得混乱。在这种情况下,可以使用YaLinqo库* ,库为数组和对象实现类似于SQL的查询语法。对于所有情况,它都有一个漂亮的语法:

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

在这里,'$v->count'function ($v) { return $v->count; }(两者都可以使用)的简写。这些方法链返回迭代器,但是->toArray()如果需要,可以通过在最后添加来获得数组。

*由我开发


1

您可以使用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'));

请解释为什么OP需要一个完整的附加库来提供看似由内置函数解决的功能
ggdx

1

这是我为实用程序类所拥有的

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

称它为:

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

1

您可以像这样使用usort

如果要按数字排序:

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

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

usort($a, "cmp");

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

查看更多:https : //www.php.net/manual/zh/function.usort.php

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.