【问题标题】:PHP Sort a multidimensional array by element containing datePHP按包含日期的元素对多维数组进行排序
【发布时间】:2011-02-24 00:48:44
【问题描述】:

我有一个数组,例如:

Array
(
[0] => Array
    (
        [id] => 2
        [type] => comment
        [text] => hey
        [datetime] => 2010-05-15 11:29:45
    )

[1] => Array
    (
        [id] => 3
        [type] => status
        [text] => oi
        [datetime] => 2010-05-26 15:59:53
    )

[2] => Array
    (
        [id] => 4
        [type] => status
        [text] => yeww
        [datetime] => 2010-05-26 16:04:24
    )

)

谁能建议一种基于日期时间元素对其进行排序/排序的方法?

【问题讨论】:

    标签: php datetime arrays sorting


    【解决方案1】:

    大多数较早的答案都未能确认将日期时间值作为简单字符串进行比较的可用快捷方式。意识到strtotime() 是不必要的其他答案并没有说明他们为什么这样做......所以我会的。

    因为您的 datetime 值的格式为单位递减(YmdHis)并且因为每个单位都用相同数量的字符(4、2、2、2、2、2)并且因为分隔字符在字符串之间都是相同的,您可以简单地从左到右逐个字符地比较它们(自然)。对于格式为 d/m/Y 的日期字符串,情况并非如此。

    有两个函数非常适合此任务,我将演示两者的 ASC 和 DESC 版本。

    Demo Link

    • usort() 按日期列 DESC:

      usort($array, function($a, $b) { return $b['datetime'] <=> $a['datetime']; });
      
    • usort() 按日期列 ASC:

      usort($array, function($a, $b) { return $a['datetime'] <=> $b['datetime']; });
      
    • usort() by date column ASC in >= PHP7.4:

      usort($array, fn($a, $b) => $a['datetime'] <=> $b['datetime']);
      
    • array_multisort() 按日期列 DESC:

       array_multisort(array_column($array, 'datetime'), SORT_DESC, $array);
      
    • array_multisort() 按日期列 ASC:

      array_multisort(array_column($array, 'datetime'), $array);
      

    所有这些技术都通过引用进行修改,因此该函数没有提供真正有价值的返回值。

    array_multisort():

    • 不需要自定义函数
    • 确实需要通过某种循环机制来隔离日期时间列
    • 它会丢失数字键,但幸运的是它们对这个问题没有价值

    usort():

    • 不使用排序方向常量,因此开发人员必须了解$a$b 之前(在宇宙飞船运算符的两侧)表示ASC,$b$a 之前表示DESC
    • 需要自定义函数
    • 可以通过调用uasort() 来调整以保留第一级密钥

    对于真正需要解析日期或日期时间字符串的人,因为它的格式不允许即时字符串比较,这里是an answer devoted to explaining the caveats of that task

    【讨论】:

    • 从 PHP 7.0.7 (?) 开始,使用 array_multisort 的解决方案发出一个通知(“只有变量引用应该通过引用返回/传递”)。要解决此问题,请将 array_column(...) 移动到新变量:array_multisort($dates, $array)
    • 请创建一个 3v4l.org 演示来支持此声明。我无法复制您的错误。 3v4l.org/E6cCJ你的实现可能有问题。
    【解决方案2】:

    对于那些仍在使用 sortByDate 函数的类中寻找解决方法的人,请参阅下面的代码

    <?php
    
    class ContactsController 
    {
        public function __construct()
        {
        //
        }
    
    
        function sortByDate($key)
        {
            return function ($a, $b) use ($key) {
                $t1 = strtotime($a[$key]);
                $t2 = strtotime($b[$key]);
                return $t2-$t1;
            };
    
        }
    
        public function index()
        {
    
            $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-11 12:38:23','created_at' =>'2020-06-11 12:38:23');
            $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-16 12:38:23','created_at' =>'2020-06-10 12:38:23');
            $data[] = array('contact' => '434343434', 'name' => 'dickson','updated_at' =>'2020-06-7 12:38:23','created_at' =>'2020-06-9 12:38:23');
    
    
            usort($data, $this->sortByDate('updated_at'));
    
            //usort($data, $this->sortByDate('created_at'));
            echo $data;
    
        }
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用带有回调函数的usort() 简单地解决这个问题。无需编写任何自定义函数。

      $your_date_field_name = 'datetime';
      usort($your_given_array_name, function ($a, $b) use (&$your_date_field_name) {
          return strtotime($a[$your_date_field_name]) - strtotime($b[$your_date_field_name]);
      });
      

      【讨论】:

        【解决方案4】:

        这应该可以。我通过 strtotime 将日期转换为 unix 时间。

          foreach ($originalArray as $key => $part) {
               $sort[$key] = strtotime($part['datetime']);
          }
          array_multisort($sort, SORT_DESC, $originalArray);
        

        单行版本将使用多个数组方法:

        array_multisort(array_map('strtotime',array_column($originalArray,'datetime')),
                        SORT_DESC, 
                        $originalArray);
        

        【讨论】:

        • 这很好用。只需将: $originalArray 替换为您的多维数组的名称。并将:'datetime' 替换为日期的子数组字段的名称。谢谢。
        • 这个解决方案对我来说效果很好。排序选项也很棒(SORT_ASC 或 SORT_DESC)。非常感谢。
        • 有一个小警告(或者我做错了什么)很好地工作......我需要排序的日期字段的日期格式为 dd/mm/yyyy 或 yyyy/ mm/dd(带斜线)。在这种情况下,由于某种原因排序不起作用(仅按天排序,而不是整个日期)。我预处理了日期以将它们转换为 dd-mm-yyyy 或 yyyy-mm-dd 并且它有效,非常感谢!!! (关于为什么它适用于连字符而不是斜线的任何想法?)
        • array_multisort 是唯一可以按 pubdate 对我的 json 文件进行排序的排序方法。谢谢。
        【解决方案5】:

        对于'd/m/Y' 日期:

        usort($array, function ($a, $b, $i = 'datetime') { 
            $t1 = strtotime(str_replace('/', '-', $a[$i]));
            $t2 = strtotime(str_replace('/', '-', $b[$i]));
        
            return $t1 > $t2;
        });
        

        其中$i 是数组索引

        【讨论】:

          【解决方案6】:

          按指定的mysql日期时间字段和顺序对记录/关联数组进行排序:

          function build_sorter($key, $dir='ASC') {
              return function ($a, $b) use ($key, $dir) {
                  $t1 = strtotime(is_array($a) ? $a[$key] : $a->$key);
                  $t2 = strtotime(is_array($b) ? $b[$key] : $b->$key);
                  if ($t1 == $t2) return 0;
                  return (strtoupper($dir) == 'ASC' ? ($t1 < $t2) : ($t1 > $t2)) ? -1 : 1;
              };
          }
          
          
          // $sort - key or property name 
          // $dir - ASC/DESC sort order or empty
          usort($arr, build_sorter($sort, $dir));
          

          【讨论】:

            【解决方案7】:

            从php7你可以使用Spaceship operator:

            usort($array, function($a, $b) {
              return new DateTime($a['datetime']) <=> new DateTime($b['datetime']);
            });
            

            【讨论】:

            • 这将数组升序变换如何降序变换?
            • @Nirav 将$a$b 交换(在自定义函数声明内或DateTime() 调用内。
            【解决方案8】:

            $array = Array
            (
              [0] => Array
               (
                [id] => 2
                [type] => comment
                [text] => hey
                [datetime] => 2010-05-15 11:29:45
               )
            
             [1] => Array
              (
                [id] => 3
                [type] => status
                [text] => oi
                [datetime] => 2010-05-26 15:59:53
              )
            
              [2] => Array
               (
                [id] => 4
                [type] => status
                [text] => yeww
                [datetime] => 2010-05-26 16:04:24
               )
            
               );
               print_r($array);   
               $name = 'datetime';
               usort($array, function ($a, $b) use(&$name){
                  return $a[$name] - $b[$name];});
            
               print_r($array);
            

            【讨论】:

              【解决方案9】:

              我偶然发现了这篇文章,但我想在归还班级内的物品时按时间排序,但出现错误。

              所以我研究了 php.net 网站并最终这样做了:

              class MyClass {
                 public function getItems(){
                    usort( $this->items, array("MyClass", "sortByTime") );
                    return $this->items;
                 }
                 public function sortByTime($a, $b){
                    return $b["time"] - $a["time"];
                 }
              }
              

              您可以在PHP.net website 中找到非常有用的示例

              我的数组看起来像这样:

                'recent' => 
                  array
                    92 => 
                      array
                        'id' => string '92' (length=2)
                        'quantity' => string '1' (length=1)
                        'time' => string '1396514041' (length=10)
                    52 => 
                      array
                        'id' => string '52' (length=2)
                        'quantity' => string '8' (length=1)
                        'time' => string '1396514838' (length=10)
                    22 => 
                      array
                        'id' => string '22' (length=2)
                        'quantity' => string '1' (length=1)
                        'time' => string '1396514871' (length=10)
                    81 => 
                      array
                        'id' => string '81' (length=2)
                        'quantity' => string '2' (length=1)
                        'time' => string '1396514988' (length=10)
              

              【讨论】:

                【解决方案10】:

                使用usort() 和自定义比较函数:

                function date_compare($a, $b)
                {
                    $t1 = strtotime($a['datetime']);
                    $t2 = strtotime($b['datetime']);
                    return $t1 - $t2;
                }    
                usort($array, 'date_compare');
                

                编辑:您的数据以数组的形式组织。为了更好地区分它们,我们将内部数组(数据)称为记录,以便您的数据确实是一个记录数组。

                usort 将一次将其中两条记录传递给给定的比较函数date_compare()date_compare 然后将每条记录的"datetime" 字段提取为UNIX 时间戳(整数),并返回差值,这样如果两个日期相等,则结果将是0,如果第一个日期(如果第二个参数 ($b) 较大,则 $a) 较大或为负值。 usort() 使用此信息对数组进行排序。

                【讨论】:

                • 在这个例子中,$array 是否需要包含元素 $a 和 $b? - 我得到一个错误,无效的比较函数
                • 不,$a$b 会将数组保存在 $array 中。确保您没有拼错函数名称。
                • 我不确定我是否理解。在我的示例中,我在数组中有 3 个数组 - 我已经确认了名称,但仍然得到无效的比较函数
                • 查看我添加的解释。我测试了代码,它对我来说很好!
                • 我不知道 CodeIgniter,但你是在类中定义函数吗?比您必须在类之外定义它或使用不同的回调参数:usort($array, array($this, "date_compare")),以便usort() 知道它是一个类函数/方法。另见:php.net/manual/en/…
                【解决方案11】:

                http://us2.php.net/manual/en/function.array-multisort.php 见第三个例子:

                <?php
                
                $data[] = array('volume' => 67, 'edition' => 2);
                $data[] = array('volume' => 86, 'edition' => 1);
                $data[] = array('volume' => 85, 'edition' => 6);
                $data[] = array('volume' => 98, 'edition' => 2);
                $data[] = array('volume' => 86, 'edition' => 6);
                $data[] = array('volume' => 67, 'edition' => 7);
                
                foreach ($data as $key => $row) {
                    $volume[$key]  = $row['volume'];
                    $edition[$key] = $row['edition'];
                }
                
                array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data);
                
                ?>
                

                fyi,使用 unix(从 1970 年开始的秒数)或 mysql 时间戳(YmdHis - 20100526014500)对解析器来说会更容易,但我认为在你的情况下它没有区别。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-11-30
                  • 1970-01-01
                  • 2016-10-31
                  • 1970-01-01
                  • 2014-10-19
                  • 1970-01-01
                  相关资源
                  最近更新 更多