如何基于关联字段(如国家)提取嵌套唯一数据结构

本文介绍如何从数据库查询返回的对象数组中,按指定字段(如 country)分组并构建多级嵌套结构,实现“国家 → 省份 → 城市”的层级化去重与关联组织。

在实际 Web 开发中,常需将扁平的数据库结果(如 country, province, city)转换为具有逻辑层级关系的数据结构,便于模板渲染或 API 响应。关键不在于简单去重(如 array_unique),而是在保留原始关联的前提下,按主键字段(如 'country')聚合子维度('province' 和 'city')。

最直接、高效且可读性强的方式是使用 嵌套关联数组 进行一次遍历构建:

$result = [];

foreach ($db_data as $item) {
    $country  = $item->country;
    $province = $item->province;
    $city     = $item->city;

    // 自动创建多级键:$result['Canada']['Ontario']['Toronto'] = $item
    $result[$country][$province][$city] = $item;
}

该方案天然支持重复值覆盖(若同一城市出现多次,后者覆盖前者),且完全保留原始对象的所有属性(如 living_cost),后续可随时扩展访问。例如:

// 获取加拿大安大略省的所有城市名
$citiesInOntario = array_keys($result['Canada']['Ontario'] ?? []);

// 遍历所有国家及其省份
foreach ($result as $country => $provinces) {
    echo "- {$country}\n";
    foreach ($provinces as $province => $cities) {
        echo "  - {$province}\n";
        foreach (array_keys($cities) as $city) {
            echo "    - {$city}\n";
        }
    }
}

优势说明

  • 零依赖:仅用原生 PHP 数组语法,无需额外函数或扩展;
  • 高性能:O(n) 时间复杂度,单次遍历完*部分组;
  • 强关联性:每个城市仍绑定其原始对象,可安全访问 living_cost 等任意字段;
  • 自动去重:同名城市在同一省份下仅保留一份(键名唯一),符合“逻辑唯一”需求。

⚠️ 注意事项

  • 若需严格保留重复城市(如不同时间戳记录),请改用 [] 追加($result[$country][$province][] = $item;);
  • 字段名需确保存在且非 null,建议在循环内添加 isset() 或 !empty() 校验以增强健壮性;
  • 输出前可用 ksort() 对国家/省份键排序,提升可读性(如 ksort($result); foreach ($result as $country => $provinces) { ksort($provinces); ... })。

此方法兼顾简洁性与工程实用性,是处理层级化地理数据、分类标签、多维统计等场景的经典实践。