根据包含 AM/PM 格式时间范围的列对 2d 数组进行排序

Sort a 2d array based on a column containing AM/PM-formatted time ranges

提问人:Ishrat Hossain 提问时间:11/22/2022 最后编辑:mickmackusaIshrat Hossain 更新时间:11/23/2022 访问量:134

问:

我有一个名为 $props 的 2D 数组,结构如下,

$props = [
    ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
    ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
    ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
];

我需要按“时间”键对数组进行排序,以获得以下结果:

[
    ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
    ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
    ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
];

我找到了usort的解决方案,解决方案如下:

usort($props, function ($a, $b) {
    return $a["time"] - $b["time"];
});

但是,这可能是由于我的时间的特殊格式(但我必须遵循这种特定的时间格式)并且显示错误并且不对数组执行任何操作,这不起作用。错误:

注意:在 C:\xampp 中遇到格式不正确的数值.....

PHP 数组排序 时间 usort

评论

1赞 M. Eriksson 11/22/2022
$a["time"] - $b["time"]尝试用另一个字符串减去一个字符串,由于显而易见的原因,这不起作用(并且没有意义)。如果可以,请以更好的格式(如 、 等)将开始时间添加为单独的键,然后改用它。类似的东西113013311501return $a['sortTime'] <=> $b['sortTime'];
0赞 mickmackusa 11/22/2022
相关新闻: 如何按时间顺序对时间数组进行排序? 以及如何在 PHP 中按子午线(AM/PM) 对时间进行排序,我需要按时间对这个 php 数组进行排序。AM PM 格式12 小时时钟数组排序,并且由于您的输入看起来像数据库查询结果:按时间 am 和 pm 排序,MYSQL 按时间 am/pm 排序
0赞 Nico Haase 11/22/2022
“但是,这可能是因为我时间的特殊格式而不起作用” - 那么为什么不调整该闭合中的数据呢?usort

答:

1赞 hakre 11/22/2022 #1

给定日期(等)的格式,需要使其可排序,同时保持原始值。03:01:PM - 04:50:PM

从您的问题中可以看出,只有第一部分()用于排序。即使不是这种情况,让我们保留它作为示例(它可以很容易地扩展)。03:01:PM

给定 C 语言环境,转换时间允许获得一个可以排序的字符串(二进制字符串顺序):

          03:01:PM
         /   |    \
    (\d\d):(\d\d):(AM|PM)
       \1     \2     \3
              -->   
             \3\1\2
             PM0301

给定一个作为输入的单个,转换可以通过正则表达式搜索和替换来完成:$time

preg_replace(
    '~^(\d+):(\d+):(AM|PM) - .*$~',
    '\3\1\2',
    $time
);
# ~> "PM0301"

现在要实际对数组进行排序,请对所有转换后的数组进行排序,并且:$props$times$props

$times = preg_replace(
    '~^(\d\d):(\d\d):(AM|PM) - .*$~',
    '\3\1\2',
    array_column($props, 'time')
);

array_multisort($times, $props);

现在按以下方式排序:$props$times

[
        [
            'name' => 'History',
            'time' => '11:30:AM - 01:30:PM',
        ],
        [
            'name' => 'French',
            'time' => '01:31:PM - 03:00:PM',
        ],
        [
            'name' => 'Mathematics',
            'time' => '03:01:PM - 04:50:PM',
        ],
];

3v4l.org 的例子

1赞 jspit 11/22/2022 #2

该解决方案具有特殊的排序功能。日期对象是使用 和 创建的。宇宙飞船操作员用于比较。usortsubstrDateTime::createFromFormat

$arr = [
  ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
  ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
  ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
];

usort($arr,function($a,$b){
  $dta = DateTime::createFromFormat('h:i:A',substr($a['time'],0,8));
  $dtb = DateTime::createFromFormat('h:i:A',substr($b['time'],0,8));
  return $dta <=> $dtb;
});

print_r($arr);

尝试自己:https://3v4l.org/Fq9U5

此变体按时间间隔的开始排序。如果只需要结束,您可以使用

DateTime::createFromFormat('h:i:A - h:i:A',$a['time']); //same with $b

评论

0赞 mickmackusa 11/23/2022
解析范围内的两个时间表达式,并生成仅考虑结束时间的 datetime 对象(这可能并不适合所有用例)3v4l.org/FAFush:i:A - h:i:A
0赞 jspit 11/23/2022
@mickmackusa : 是的,它按开始时间或结束时间排序。我不知道如何进行将开始时间和结束时间考虑在内的排序。
1赞 mickmackusa 11/22/2022 #3

对于没有正则表达式和最少迭代函数调用的方法,请与迭代调用一起使用 ,并使用生成的排序数组作为对输入数组进行排序的第一个参数。array_map()createFromFormat()array_multisort()

请注意,createFromFormat() 方法中的 + 要求忽略所有剩余字符。

代码:(演示)

array_multisort(
    array_map(
        fn($row) => DateTime::createFromFormat('h:i:A+', $row['time']),
        $props
    ),
    $props
);

var_export($props);

评论

0赞 jspit 11/22/2022
当 DateTime::getLastErrors() 中的警告不是问题时,格式中的 + 是一个很好的解决方案。
0赞 mickmackusa 11/22/2022
@jspit我想你知道一些我不知道的事情。请解释。
0赞 jspit 11/22/2022
返回 “'warnings' => array ( 8 => 'Trailing data')”。如果我用“+”指示应该忽略剩余的数据,那完全是多余的。3v4l.org/cf9Wb