【问题标题】:Sort array of objects by object fields按对象字段对对象数组进行排序
【发布时间】:2011-05-16 00:11:54
【问题描述】:

如何按其中一个字段(如namecount)对该对象数组进行排序?

  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
        )

   ....

【问题讨论】:

    标签: php arrays sorting object


    【解决方案1】:

    使用usort,这是一个改编自手册的示例:

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

    您也可以使用任何callable 作为第二个参数。以下是一些示例:

    • 使用anonymous functions(来自 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
      
    • 使用arrow functions(来自 PHP 7.4)

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

    另外,如果您要比较数值,fn($a, $b) => $a->count - $b->count 作为“比较”函数应该可以解决问题,或者,如果您想要另一种方法来做同样的事情,从 PHP 7 开始,您可以使用 @ 987654325@,像这样:fn($a, $b) => $a->count <=> $b->count

    【讨论】:

    • 这很好,但是如果排序函数和调用函数在同一个类中,你应该使用:usort($your_data, array($this, "cmp"));
    • @rmooney 是的,但前提是你在课堂上。
    • 在你的答案中输入first comment by @rmooney
    • 或者,如果您的比较函数在您正在比较的模型/对象中(我认为这是一个更简洁的设计),您必须将完整的命名空间包含到您的模型/对象中,如下所示:uasort($ members, array("Path\to\your\Model\Member", "compareByName"));
    • 这不会给我任何排序的结果,只是最大的第一个,其余的我都没有排序
    【解决方案2】:

    这是使用闭包的更好方法

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

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

    【讨论】:

    • 我比公认的答案更喜欢这个,因为我们可以快速定义比较函数并可以在类中使用
    • 如果你想保留数组键使用uasort()
    • 对于降序排序,-1 * strcmp($a->name, $b->name);
    • 无需乘以降序排序。只需交换参数:strcmp($b->name, $a->name)
    • 您可能会遇到像我这样的情况,接受的答案比这个更可取。例如,您可能有一个父类和一个子类。子类覆盖了一个使用usort 的函数,但比较函数是相同的。使用它,您需要复制闭包的代码,而不是调用 protected static 方法,您只需在父类中定义一次。
    【解决方案3】:

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

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

    【讨论】:

    • 对我来说,$first->number 不起作用。我需要改用 $first["number"]。
    • 您可以使用 PHP 原生 strcasecmp() 函数比较字符串并忽略大小写,而不是使用 strtolower()(阅读 PHP: strcasecmp - Manual
    【解决方案4】:

    如果您使用的是 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')); 
    

    【讨论】:

      【解决方案5】:
      usort($array, 'my_sort_function');
      
      var_dump($array);
      
      function my_sort_function($a, $b)
      {
          return $a->name < $b->name;
      }
      

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

      更多关于usort的详情:http://ru2.php.net/usort

      顺便说一句,你从哪里得到这个数组的?我希望不是来自数据库?

      【讨论】:

      • 其实$result成功的话会包含TRUE,你的比较应该是$a-&gt;name &gt; $b-&gt;name。 :)
      • @cambraca:哦,忘了它通过引用接受数组。顺便说一句,OP 没有说他需要哪个顺序来对集合进行排序。
      • 嗯,是的,它是一个数据库 :) 实际上来自一个从数据库中获取数据的函数
      • @Alex:那你为什么不在数据库中排序呢? ORDER BY count
      • 它更复杂,因为这是 wordpress 的标准功能部分,并且在我编写插件时,我无法更改 wp 文件。我使用 create_function 尝试了您的示例(因为我在类中使用它并且我不知道如何将函数名称传递给 usort):create_function('$a,$b', "return $a-&gt;count &lt; $b-&gt;count;") 但我无法使其工作:( 我收到一些通知并警告 usort 期望参数 2 是有效的回调
      【解决方案6】:

      您可以使用此功能(适用于 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-&gt;{$key}$b-&gt;{$key} 而不是$a[$key]$b[$key],严格来说,处理的是属性而不是数组成员,但这仍然是我一直在寻找的答案为。
      • 请在示例代码中实施@SteJ 的建议,因为您提供的解决方案仅适用于简单对象,但通过 SteJ 的修复,它适用于我尝试过的所有对象数组
      【解决方案7】:

      如果这里一切都失败了,还有另一种解决方案:

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

      【讨论】:

      • 你应该为这个解决方案获得奥斯卡奖! ))))) 谢谢你
      【解决方案8】:

      你可以使用usort,像这样:

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

      【讨论】:

        【解决方案9】:

        这里所有答案的缺点是它们使用 static 字段名称,因此我以 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;
            }
        } 
        

        【讨论】:

          【解决方案10】:

          如果你想对日期进行排序

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

          【讨论】:

            【解决方案11】:

            如果您需要基于本地的字符串比较,可以使用strcoll 而不是strcmp

            如果需要,请记住首先使用setlocaleLC_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);
              });
            

            【讨论】:

              【解决方案12】:

              一个简单的替代方案,允许您动态确定排序所基于的字段:

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

              这是基于Closure class,它允许匿名函数。它从 PHP 5.3 开始可用。

              【讨论】:

                【解决方案13】:

                如果你在 Codeigniter 中使用这个,你可以使用方法:

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

                @rmooney 谢谢你的建议。这对我很有帮助。

                【讨论】:

                • 这个 Codeigniter 的具体情况如何?
                【解决方案14】:

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

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

                【讨论】:

                  【解决方案15】:

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

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

                  这里,'$v-&gt;count'function ($v) { return $v-&gt;count; } 的简写(两者都可以)。这些方法链返回迭代器,但如果需要,您可以通过在末尾添加-&gt;toArray() 来获取数组。

                  *我开发的

                  【讨论】:

                    【解决方案16】:

                    你可以使用Nspl中的sorted函数:

                    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 需要一个完整的附加库来提供一个似乎可以通过内置函数解决的设施
                    【解决方案17】:

                    这就是我拥有的实用程序类

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

                    【讨论】:

                      【解决方案18】:

                      你可以像这样使用 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 字符:

                      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/en/function.usort.php

                      【讨论】:

                        【解决方案19】:
                        $array[0] = array('key_a' => 'z', 'key_b' => 'c');
                        $array[1] = array('key_a' => 'x', 'key_b' => 'b');
                        $array[2] = array('key_a' => 'y', 'key_b' => 'a');
                        
                        function build_sorter($key) {
                            return function ($a, $b) use ($key) {
                                return strnatcmp($a[$key], $b[$key]);
                            };
                        }
                        
                        usort($array, build_sorter('key_b'));
                        

                        【讨论】:

                          【解决方案20】:

                          Demodave吃多键的参考答案

                           function array_sort_by(array $arr, $keys){
                          
                              if(!is_array($keys))
                                  $keyList = explode(',', $keys);
                              $keyList = array_keys(array_flip($keyList)); // array_unique 
                              $keyList = array_reverse($keyList);
                          
                              $result = &$arr;
                              foreach ($keyList as $key) {
                                  if(array_key_exists($key, $arr))
                                      $result = usort($result, function($a, $b) use ($key) { return strcmp($a->{$key}, $b->{$key}); });
                              }
                              return $result;
                          }
                          

                          【讨论】:

                            【解决方案21】:

                            使用这个....

                            $array_list = [
                                "Apple" => 2,
                                "Pear" => 1,
                                "Orange" => 5,
                                "Lemon" => 1,
                                "Strawberry" => 2,
                                "Banana" => 3
                            ];
                            
                            function cmp($a, $b) {
                                return $b - $a;
                            }
                            
                            $ao = new ArrayObject($object);
                            $ao->uasort('cmp');
                            print_r(json_encode($ao));
                            

                            由!!!!

                            【讨论】:

                            • 使用 uasort,这工作!!!
                            猜你喜欢
                            • 2015-03-11
                            • 1970-01-01
                            • 2014-10-01
                            • 2011-10-30
                            • 1970-01-01
                            • 2017-05-01
                            相关资源
                            最近更新 更多