我有以下陣列
$array = [
'2022-06-30',
'2022-04-20',
'2021-04-07',
'2022-09-09',
'2022-03-08',
'2021-08-07',
'2022-10-12'
];
我想對過去 ASC 中的每個日期和未來 DESC 中的每個日期進行排序。
我怎樣才能做到這一點?
有了“今天” 2022-06-02,我的預期結果是:
array (
0 => '2021-04-07', // before today, ASC
1 => '2021-08-07', // before today, ASC
2 => '2022-03-08', // before today, ASC
3 => '2022-04-20', // before today, ASC
4 => '2022-10-12', // after today, DESC
5 => '2022-09-09', // after today, DESC
6 => '2022-06-30', // after today, DESC
)
uj5u.com熱心網友回復:
這是usort()的作業,具有您提供的比較功能。
您的比較函式被稱為cmp($a, $b). $a 和 $b 是陣列中的兩個專案。如果 $a 在輸出中位于 $b 之前,則回傳 -1。如果 $a 在 $b 之后,則回傳 1。如果它們相同,則回傳 0。因此,您需要一個比較函式來實作特定的前后邏輯。
usort()每當需要將一個日期與另一個日期進行比較以進行排序時,該函式就會呼叫您的比較函式。它使用不同的值對呼叫您的函式O(n log(n))次。
像這樣的東西?NOT,重復NOT,除錯。
$nowTimeForMySort = time();
function cmpDates ($a, $b) {
global $nowTimeForMySort;
/* equal times, return 0 */
if ($a == $b) return 0;
$aTime = strtotime($a);
$bTime = strtotime($b);
/* if one date is in the past and the other in the future,
* always put the date in the past before the date in the future. */
if ($aTime <= $nowTimeForMySort && $bTime > $nowTimeForMySort) return -1;
if ($aTime > $nowTimeForMySort && $bTime <= $nowTimeForMySort) return 1;
/* when we get here, both dates are either past or future. */
if ($aTime <= $nowTimeForMySort) {
/* past dates: ascending */
if ($aTime < $bTime) return -1;
if ($aTime > $bTime) return 1;
} else {
/* future dates: descending */
if ($aTime < $bTime) return 1;
if ($aTime > $bTime) return -1;
}
return 0;
}
然后像這樣使用該功能usort()。
usort($a, 'cmpDates');
專業提示:您必須絕對確定您的比較函式的輸出確定性地僅取決于它的兩個輸入,而不取決于任何可能改變的東西。這就是為什么此示例將當前時間填充到全域變數中的原因:我們不希望在排序程序中更改時間,否則結果可能會非常奇怪。
專業提示某些語言的比較函式允許回傳負數/零/正數。php 要求您回傳 -1, 0, 1。
uj5u.com熱心網友回復:
您的邏輯要求僅在兩個日期都大于今天時才對 DESC 進行排序。在usort()使用三元條件的自定義回呼中傳遞正確的乘數來調整排序方向。
代碼:(演示)
$array = [
'2022-06-30',
'2022-04-20',
'2021-04-07',
'2022-09-09',
'2022-03-08',
'2021-08-07',
'2022-10-12'
];
$today = '2022-06-02'; // date('Y-m-d');
usort($array, fn($a, $b) => ($a > $today && $b > $today ? -1 : 1) * ($a <=> $b));
var_export($array);
輸出:
array (
0 => '2021-04-07',
1 => '2021-08-07',
2 => '2022-03-08',
3 => '2022-04-20',
4 => '2022-10-12',
5 => '2022-09-09',
6 => '2022-06-30',
)
更簡潔但效率較低的方法可能如下所示:(演示)
usort($array, fn($a, $b) => (min($a, $b) > $today ? -1 : 1) * ($a <=> $b));
uj5u.com熱心網友回復:
有趣的用例。為此,在自定義排序之后,第一部分將按升序顯示過去日期,而陣列的第二部分將按降序顯示當前/未來日期。為此,您可以使用usort如下:
- 如果 2 個日期是當前/未來日期,則比較并安全地回傳值,較大的日期先于較小的日期。
- 如果 2 個日期不滿足上述步驟,請按原樣比較它們并回傳值。
片段:
<?php
$today_dt = DateTime::createFromFormat('Y-m-d H:i:s', date("Y-m-d") . " 00:00:00");
usort($array, function($a, $b) use ($today_dt){
$d1 = DateTime::createFromFormat('Y-m-d H:i:s', $a . " 00:00:00");
$d2 = DateTime::createFromFormat('Y-m-d H:i:s', $b . " 00:00:00");
if($d1 >= $today_dt && $d2 >= $today_dt){
return $d2 <=> $d1; // DESC
}
return $d1 <=> $d2; // ASC
});
在線演示
更新:
正如@IMSoP 在評論中提到的,您可以使代碼更簡潔,而無需手動附加午夜時間字串。More info
<?php
$array = ['2022-09-09', '2022-06-30', '2022-04-20', '2021-04-07', '2022-03-08', '2021-08-07', '2022-10-12'];
$today_dt = new DateTime('today midnight');
usort($array, function($a, $b) use ($today_dt){
$d1 = DateTime::createFromFormat('!Y-m-d', $a);
$d2 = DateTime::createFromFormat('!Y-m-d', $b);
if($d1 >= $today_dt && $d2 >= $today_dt){
return $d2 <=> $d1; // DESC
}
return $d1 <=> $d2; // ASC
});
print_r($array);
在線演示
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/487394.html
