提问人:Ishrat Hossain 提问时间:11/22/2022 最后编辑:mickmackusaIshrat Hossain 更新时间:11/23/2022 访问量:134
根据包含 AM/PM 格式时间范围的列对 2d 数组进行排序
Sort a 2d array based on a column containing AM/PM-formatted time ranges
问:
我有一个名为 $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 中遇到格式不正确的数值.....
答:
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',
],
];
评论
0赞
mickmackusa
11/22/2022
preg_replace('~(\d\d:\d\d):([AP]).*~', '\2\1', array_column($props, 'time'))
1赞
jspit
11/22/2022
#2
该解决方案具有特殊的排序功能。日期对象是使用 和 创建的。宇宙飞船操作员用于比较。usort
substr
DateTime::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);
此变体按时间间隔的开始排序。如果只需要结束,您可以使用
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
评论
$a["time"] - $b["time"]
尝试用另一个字符串减去一个字符串,由于显而易见的原因,这不起作用(并且没有意义)。如果可以,请以更好的格式(如 、 等)将开始时间添加为单独的键,然后改用它。类似的东西1130
1331
1501
return $a['sortTime'] <=> $b['sortTime'];
usort