
本文介绍如何将“商品→多个分类”的原始数据结构,高效转换为“分类→多个商品”的逆向关联数组,适用于电商标签系统、内容归类等场景。
在实际开发中,我们常遇到需要对多对多关系进行“方向翻转”的需求:原始数据以商品为主体,每个商品归属多个分类(如 ["apparel", "head"]),但业务逻辑却要求按分类快速检索所有关联商品(如 apparel => ["Hat", "Scarf"])。这种逆向映射(inverted map)是构建分类导航、标签聚合或搜索筛选功能的核心步骤。
以下是一个简洁、可读性强且性能合理的 PHP 实现方案:
"Hat", "price" => 10.99, "categories" => ["apparel", "head"]],
["itemName" => "Scarf", "price" => 7.99, "categories" => ["apparel", "neck"]],
["itemName" => "Watch", "price" => 19.99, "categories" => ["jewelry", "electronics"]],
["itemName" => "Necklace", "price" => 99.99, "categories" => ["jewelry", "neck"]],
["itemName" => "Headphones", "price" => 29.99, "categories" => ["head", "electronics"]]
];
// 步骤 1:提取并去重所有唯一分类
$allCategories = array_unique(
array_merge(...array_values(array_column($items, 'categories')))
);
// 步骤 2:遍历每个唯一分类,收集匹配的商品名
$categories = [];
foreach ($allCategories as $category) {
foreach ($items as $item) {
if (in_array($category, $item['categories'])) {
$categories[$category][] = $item['itemName'];
}
}
}
print_r($categories);✅ 关键技巧说明:
- array_column($items, 'categories') 提取所有 categories 子数组,返回二维数组;
- ...array_values(...) 展开并合并所有子数组(PHP 5.6+ 的展开运算符 ...);
- array_unique() 去重,确保每个分类只处理一次,避免重复逻辑;
- 使用 $categories[$category][] = ... 动态追加,天然支持多值,无需预初始化空数组。
⚠️ 注意事项:
- 若数据量极大(如 >10,000 条),嵌套循环可能影响性能,此时建议改用单次遍历 + 分类预填充方式(见进阶优化);
- 确保 categories 字段始终为数组类型,可在循环前添加 is_array($item['categories']) 防御性检查;
- 如需保持商品顺序或去重(同一商品被多次归入同一分类),可在追加前使用 !in_array($item['itemName'], $categories[$category]) 判断。
? 进阶优化(单次遍历版):
$categories = [];
foreach ($items as $item) {
foreach ($item['categories'] as $category) {
if (!isset($categories[$category])) {
$categories[$category] = [];
}
$categories[$category][] = $item['itemName'];
}
}该版本时间复杂度为 O(N×M),其中 N 为商品数、M 为平均分类数,比双重循环更高效,且代码更直观,推荐作为默认实现。
通过以上方法,你可灵活构建任意维度的逆向索引结构,为后续的数据聚合、前端渲染或 API 输出奠定坚实基础。










