如何按日期键过滤数组,仅保留年月对应的最晚日期条目
过滤数组保留每个年月的最晚日期条目
需求
你有一个键为Y-m-d格式的数组,需要过滤后仅保留每个年月对应的最晚日期关联的条目。数组可能包含多个月份,且并非每个月的每一天都有数据。
示例
输入数组
array:4 [▼ "2022-10-30" => array:9 [▶] "2022-10-31" => array:6 [▶] "2022-11-07" => array:4 [▶] "2022-11-09" => array:3 [▶] ]
期望输出
array:2 [▼ "2022-10-31" => array:6 [▶] "2022-11-09" => array:3 [▶] ]
解决方案
你的现有代码存在几个问题:变量名拼写错误($date[i]应该是$dates[$i])、循环边界越界($i <= sizeof($dates)会访问超出数组长度的索引),而且整体思路可以更简洁。以下是两种可行的实现方式:
方式一:遍历分组(直观易懂)
public function monthly_average() { global $datas, $dates; $args = $this->period_monthAverage($datas, $dates); $grouped = []; // 遍历目标数组,按年月分组记录最晚日期 foreach ($args as $dateStr => $value) { $yearMonth = date('Y-m', strtotime($dateStr)); // 如果当前年月未记录,或当前日期比已记录的更晚,就更新 if (!isset($grouped[$yearMonth]) || strtotime($dateStr) > strtotime($grouped[$yearMonth]['date'])) { $grouped[$yearMonth] = [ 'date' => $dateStr, 'value' => $value ]; } } // 整理成期望的键值格式 $final = []; foreach ($grouped as $item) { $final[$item['date']] = $item['value']; } dump($final); }
方式二:数组函数组合(简洁高效)
如果追求代码简洁,可以用array_reduce和array_intersect_key组合实现:
public function monthly_average() { global $datas, $dates; $args = $this->period_monthAverage($datas, $dates); // 第一步:找出每个年月的最晚日期 $latestDates = array_reduce(array_keys($args), function($carry, $date) use ($args) { $yearMonth = date('Y-m', strtotime($date)); if (!isset($carry[$yearMonth]) || strtotime($date) > strtotime($carry[$yearMonth])) { $carry[$yearMonth] = $date; } return $carry; }, []); // 第二步:从原数组中筛选出这些日期的条目 $final = array_intersect_key($args, array_flip($latestDates)); dump($final); }
代码说明
- 核心思路是按年月分组,通过时间戳比较找出每个组内的最大日期
- 时间戳对比(
strtotime)是最可靠的日期比较方式,避免字符串直接对比的潜在问题 - 两种方式都能处理任意数量的月份,且不依赖数组是否按日期排序
内容的提问来源于stack exchange,提问作者Aleyn
相关产品推荐
相关产品推荐

