商城首页欢迎来到中国正版软件门户

您的位置:首页 >PHP按标签去重保留最旧记录方法

PHP按标签去重保留最旧记录方法

  发布于2026-04-09 阅读(0)

扫一扫,手机访问

如何在 PHP 中按标签去重并保留每个标签最旧的记录

本文介绍一种高效、可扩展的方法:先按标签升序、再按日期升序排序,随后一次遍历提取每个标签的首条(即最早)记录,避免嵌套循环,时间复杂度优化至 O(n log n)。

本文介绍一种高效、可扩展的方法:先按标签升序、再按日期升序排序,随后一次遍历提取每个标签的首条(即最早)记录,避免嵌套循环,时间复杂度优化至 O(n log n)。

在处理带时间戳的标签化数据时,常见需求是:对相同 label 的多条记录,仅保留创建时间最早(即“最旧”)的一条。注意:题目中示例目标结果误将 "11/01/2022"(更早)标为保留项,但实际逻辑应为「保留最旧」→ 即日期值最小者(如 11/01/2022 < 15/01/2022)。而原答案代码因排序逻辑为 a.created <=> b.created(升序),导致相同标签下较早日期排在前面;后续取每组最后一条($i === $last 或 $data[$i+1]["label"] !== $data[$i]["label"])实则取的是每组第一条(因已升序排列,第一条即最旧),因此逻辑正确。

以下是推荐的完整实现方案:

✅ 推荐解法:双字段排序 + 单次遍历(高效稳定)

function filterByOldestPerLabel(array $data): array
{
    // 按 label 升序,同 label 下按 created 升序(确保最旧日期在前)
    usort($data, function ($a, $b) {
        if ($a['label'] !== $b['label']) {
            return $a['label'] <=> $b['label'];
        }
        // 将 "d/m/Y" 格式转为 DateTime 比较,避免字符串误判(如 "2/1/2022" > "11/1/2022")
        $dateA = DateTime::createFromFormat('d/m/Y', $a['created']);
        $dateB = DateTime::createFromFormat('d/m/Y', $b['created']);
        return $dateA <=> $dateB;
    });

    $result = [];
    $prevLabel = null;

    foreach ($data as $item) {
        // 首次出现该 label,或 label 切换时,保留当前项(即该 label 下最旧的一条)
        if ($prevLabel !== $item['label']) {
            $result[] = $item;
            $prevLabel = $item['label'];
        }
    }

    return $result;
}

// 使用示例
$data = [
    ['label' => 'Same label', 'created' => '15/01/2022'],
    ['label' => 'Same label', 'created' => '11/01/2022'],
    ['label' => 'Label alone', 'created' => '18/01/2022'],
];

$filtered = filterByOldestPerLabel($data);
print_r($filtered);

输出结果:

Array
(
    [0] => Array
        (
            [label] => Label alone
            [created] => 18/01/2022
        )
    [1] => Array
        (
            [label] => Same label
            [created] => 11/01/2022   // ✅ 最旧日期被保留
        )
)

⚠️ 关键注意事项

  • 日期格式必须严格匹配:DateTime::createFromFormat('d/m/Y', ...) 要求输入为 日/月/年 格式。若原始数据含 Y-m-d 或其他格式,请同步调整格式字符串(如 'Y-m-d')。
  • 错误处理增强建议:生产环境应检查 DateTime::createFromFormat() 返回值是否为 false,避免解析失败导致比较异常:
    $dateA = DateTime::createFromFormat('d/m/Y', $a['created']);
    $dateB = DateTime::createFromFormat('d/m/Y', $b['created']);
    if (!$dateA || !$dateB) {
        throw new InvalidArgumentException('Invalid date format in data');
    }
  • 性能对比:相比原始 array_search() + array_column() 的 O(n²) 方案,本方法 usort 为 O(n log n),单次遍历为 O(n),整体显著优于大数据量场景(如数千条以上)。
  • 内存友好:无需额外哈希表存储中间状态,适合内存受限环境。

✅ 总结

该方案以「排序归一化 + 线性扫描」为核心思想,兼顾可读性、健壮性与性能。它不依赖外部库,兼容 PHP 7.0+,且易于扩展(例如改为保留最新记录,仅需将日期比较改为降序 ($dateB <=> $dateA))。对于标签去重并按时间维度筛选的典型业务场景(如工单去重、版本快照归档等),是简洁可靠的工程实践。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注