[英]Sort array of strings which may containing day and abbreviated month names
我想按升序对数组进行排序,但正常的排序方法不会尊重可选出现的日期和月份子字符串。 包含“反馈”的字符串必须按月和日排序,因为它们出现在日历上。
甚至natsort()
都不会按照我的要求尊重月份。
示例数组:
$array = [
"Feedback 13 okt",
"Feedback 11 okt",
"Feedback 12 okt",
"Sweet",
"Feedback 9 okt",
"Feedback 6 okt",
"Feedback 8 jun",
"Fixes",
"Realisation",
"Feedback 22 mar",
"Do something",
"Feedback 3 maj",
"Feedback 1 dec",
];
期望的结果:
[
'Do something',
'Feedback 22 mar',
'Feedback 3 maj',
'Feedback 8 jun',
'Feedback 6 okt',
'Feedback 9 okt',
'Feedback 11 okt',
'Feedback 12 okt',
'Feedback 13 okt',
'Feedback 1 dec',
'Fixes',
'Realisation',
'Sweet',
]
您应该使用usort()来实现自己的比较函数,该函数首先比较两个没有任何数字的字符串(为此使用preg_replace('/ \\ d + /','',$ str) ),然后,如果将两个字符串比较为平等,使用strnatcmp()来比较的字符串(包括数字) natsort()方法。
usort($array, function($a, $b) {
$cmp = strcmp(preg_replace('/\d+/', '', $a), preg_replace('/\d+/', '', $b));
if ($cmp) {
return $cmp;
} else {
return strnatcmp($a, $b);
}
});
奇怪的是,我对所需排序逻辑的解释似乎比提问者的更深入。
我认为规则如下:
代码:(演示)
$array = [
"Feedback 13 okt",
"Feedback 11 okt",
"Feedback 12 okt",
"Sweet",
"Feedback 9 okt",
"Feedback 6 okt",
"Feedback 8 jun",
"Fixes",
"Realisation",
"Feedback 22 mar",
"Do something",
"Feedback 3 maj",
"Feedback 1 dec",
];
$mmm = array_flip([
"jan", "feb", "mar", "apr",
"maj", "jun", "jul", "aug",
"sep", "okt", "nov", "dec"
]);
usort(
$array,
fn($a, $b) =>
strtok($a, ' ') <=> strtok($b, ' ')
?: (sscanf($a, "Feedback %d %s", $aDay, $aMon)
? [$mmm[$aMon] ?? 13, $aDay]
: [13, 32])
<=>
(sscanf($b, "Feedback %d %s", $bDay, $bMon)
? [$mmm[$bMon] ?? 13, $bDay]
: [13, 32])
?: natcasecmp($a, $b)
);
var_export($array);
输出:
array (
0 => 'Do something',
1 => 'Feedback 22 mar',
2 => 'Feedback 3 maj',
3 => 'Feedback 8 jun',
4 => 'Feedback 6 okt',
5 => 'Feedback 9 okt',
6 => 'Feedback 11 okt',
7 => 'Feedback 12 okt',
8 => 'Feedback 13 okt',
9 => 'Feedback 1 dec',
10 => 'Fixes',
11 => 'Realisation',
12 => 'Sweet',
)
通过使用“Elvis 运算符”( ?:
),后续的决胜局进程仅在必要时执行。 这是最佳实践并提供最佳性能。
您可以从日期部分创建DateTime
并在usort
中按时间顺序对日期条目进行排序。 我无法让我的区域设置正确地使用您的语言,因此我不得不编辑数据以使用英语月份缩写。 我假设您已为您的语言环境正确配置了 PHP,因此这应该可以在您的系统上使用您的数据。
usort($array, function($a, $b) {
$pattern = '/^\w*\s+/'; // ("Feedback ") matches first word + whitespaces
$fmt = 'j M';
$a_date = DateTime::createFromFormat($fmt, preg_replace($pattern, '', $a));
$b_date = DateTime::createFromFormat($fmt, preg_replace($pattern, '', $b));
if($a_date && $b_date) // both are dates
return $a_date <=> $b_date;
// fallback to compare as strings
return strcmp($a, $b);
});
因此,使用以下$array
值:
$array = [
"Feedback 13 oct",
"Feedback 11 oct",
"Feedback 12 oct",
"Sweet",
"Feedback 9 oct",
"Feedback 6 oct",
"Feedback 8 jun",
"Fixes",
"Realisation",
"Feedback 22 mar",
"Do something",
"Feedback 3 may",
"Feedback 1 dec",
];
调用上面的usort
function var_export($array);
将output如下:
array (
0 => 'Do something',
1 => 'Feedback 22 mar',
2 => 'Feedback 3 may',
3 => 'Feedback 8 jun',
4 => 'Feedback 6 oct',
5 => 'Feedback 9 oct',
6 => 'Feedback 11 oct',
7 => 'Feedback 12 oct',
8 => 'Feedback 13 oct',
9 => 'Feedback 1 dec',
10 => 'Fixes',
11 => 'Realisation',
12 => 'Sweet',
)
看到它在这里工作: https://onlinephp.io/c/dc5d6
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.