
本文介绍如何将多维数组中重复出现的 range 值(如 336、390)统一映射为从 0 开始的紧凑整数序列(如 336→0,390→1),保持同 ID 元素序号一致,适用于分组标识、前端索引优化等场景。
本文介绍如何将多维数组中重复出现的 `range` 值(如 336、390)统一映射为从 0 开始的紧凑整数序列(如 336→0,390→1),保持同 ID 元素序号一致,适用于分组标识、前端索引优化等场景。
在 PHP 开发中,常需对多维数组中某一字段(如 'range')的重复值进行归一化编号——即把原始不连续、非零起始的 ID(如 336, 390, 336, 390)转换为逻辑上连续、从 0 开始的组序号(0, 0, 1, 1)。这种需求常见于数据分组渲染、Elasticsearch 聚合结果处理或前端表格按类别折叠展示等场景。
核心思路是:先提取所有唯一 range 值 → 按首次出现顺序排序 → 映射为 0, 1, 2, ... 的键值对 → 批量重写原数组中的 range 字段。
以下是完整、健壮的实现方案:
<?php
// 示例输入数据
$array = [
['range' => 336, 'year' => 2020, 'month' => 222],
['range' => 336, 'year' => 2020, 'month' => 222],
['range' => 390, 'year' => 2020, 'month' => 222],
['range' => 390, 'year' => 2021, 'month' => 222],
];
// 步骤 1:提取所有 range 值,去重并重置键为连续数字(保证顺序稳定)
$uniqueRanges = array_values(array_unique(array_column($array, 'range')));
// 步骤 2:构建映射表:range_value → sequence_index
$rangeToIndex = array_flip($uniqueRanges);
// 步骤 3:遍历原数组,用映射表替换 range 值
$result = array_map(function ($item) use ($rangeToIndex) {
$item['range'] = $rangeToIndex[$item['range']] ?? 0; // 安全兜底
return $item;
}, $array);
print_r($result);
?>✅ 输出结果:
Array
(
[0] => Array
(
[range] => 0
[year] => 2020
[month] => 222
)
[1] => Array
(
[range] => 0
[year] => 2020
[month] => 222
)
[2] => Array
(
[range] => 1
[year] => 2020
[month] => 222
)
[3] => Array
(
[range] => 1
[year] => 2021
[month] => 222
)
)? 关键说明:
- array_column($array, 'range') 高效提取所有 range 值;
- array_unique() 去重,保留首次出现顺序(PHP 7.2+ 默认行为);
- array_values() 重置键为 0,1,2...,确保序号严格从 0 开始;
- array_flip() 将 [0=>336, 1=>390] 翻转为 [336=>0, 390=>1],实现 O(1) 查找;
- 使用 array_map() + use 闭包避免副作用,保持函数式风格,清晰可维护。
⚠️ 注意事项:
- 若原始数组中 range 可能为 null 或缺失,建议提前校验:array_column($array, 'range', null) 并过滤空值;
- 该方案时间复杂度为 O(n),空间复杂度 O(k)(k 为唯一 range 数量),性能优异;
- 如需按 range 值大小排序(而非首次出现顺序),可将 array_unique(...) 替换为 array_values(array_unique(...)) 后调用 sort($uniqueRanges, SORT_NUMERIC)。
此方法简洁、高效、无循环嵌套,是处理此类“ID→序号映射”问题的标准实践。