基于$filterContains与$filterExclude的产品数组过滤功能异常排查
数据结构说明
$data->products 是包含约10000个产品的数组,每个产品均带有参数,结构如下:
Array ( [0] => Array ( [id] => 440 [name] => Product1 [parameters] => Array ( [0] => Array ( [id] => 1 [name] => Parameter1 [value] => Array ( [0] => Array ( [id] => 1 [name] => ValueParameter1 ) ) ) [1] => Array ( [id] => 2 [name] => Parameter2 [value] => Array ( [0] => Array ( [id] => 2 [name] => ValueParameter2 ) ) ) [2] => Array ( [id] => 3 [name] => Parameter3 [value] => Array ( [0] => Array ( [id] => 3 [name] => ValueParameter3 ) ) ) [3] => ......... ... ) ) [1] => Array ( [id] => 14 [name] => Product2 [parameters] => Array ( [0] => Array ( [id] => 2 [name] => Parameter2 [value] => Array ( [0] => Array ( [id] => 2 [name] => ValueParameter2 ) ) ) [2] => Array ( [id] => 3 [name] => Parameter3 [value] => Array ( [0] => Array ( [id] => 3 [name] => ValueParameter3 ) ) ) [2] => Array ( [id] => 35 [name] => Parameter35 [value] => Array ( [0] => Array ( [id] => 64 [name] => ValueParameter35 ) ) ) [3] => ......... ... ) ) [2] => .... .....
需求说明
- 需对
$data->products数组进行过滤 $filterContains:参数ID数组,需保留包含该数组中所有参数ID的产品$filterExclude:参数ID数组,需排除包含该数组中任意参数ID的产品- 最终需得到同时满足上述两个规则的产品数组
现有代码
function getFilteredData($data, array $filterContains = [], array $filterExclude = []): array { $result = []; $keyCount = count($filterContains); foreach ($data->products as $product) { if (isset($product['parameters'])) { $match = 0; $product['parameters'] = array_values($product['parameters']); foreach ($product['parameters'] as $parameter) { foreach ($filterContains as $value) { if ($parameter['id'] == $value && !in_array($parameter['id'], $filterExclude)) { $match++; } } if ($match == $keyCount) { $result[] = $product; } } } } $unique_array = []; foreach ($result as $element) { $hash = $element['id']; $unique_array[$hash] = $element; } $result = array_values($unique_array); return $result; }
问题排查与修复
问题根源
现有代码存在两个核心问题:
- 仅在匹配
$filterContains的参数时才检查是否属于$filterExclude,完全忽略了产品中存在排除列表内其他参数的情况——只要产品包含任意一个排除参数,就应直接被排除,无论是否满足包含条件。 - 匹配逻辑有漏洞:若产品参数中重复出现同一个包含列表内的ID,会导致
$match错误累加,可能误判为满足全包含要求。
修复后的代码
function getFilteredData($data, array $filterContains = [], array $filterExclude = []): array { $result = []; foreach ($data->products as $product) { if (!isset($product['parameters'])) { // 无参数产品:仅当两个过滤列表都为空时保留 if (empty($filterContains) && empty($filterExclude)) { $result[] = $product; } continue; } // 提取当前产品的所有参数ID并去重 $productParamIds = array_unique(array_column($product['parameters'], 'id')); // 优先检查排除规则:只要有一个参数在排除列表中,直接跳过 if (!empty($filterExclude) && array_intersect($productParamIds, $filterExclude)) { continue; } // 检查包含规则 if (empty($filterContains)) { // 包含列表为空,且已通过排除检查,加入结果 $result[] = $product; } else { // 计算产品参数与包含列表的交集,长度匹配则说明全包含 $matched = array_intersect($productParamIds, $filterContains); if (count($matched) === count($filterContains)) { $result[] = $product; } } } // 按产品ID去重 $uniqueResult = []; foreach ($result as $item) { $uniqueResult[$item['id']] = $item; } return array_values($uniqueResult); }
修复说明
- 优先处理排除规则:先提取产品所有参数ID,只要和排除列表有交集就直接跳过,逻辑更高效清晰。
- 准确匹配包含规则:用
array_intersect计算交集,通过交集长度判断是否包含所有要求的参数,避免重复计数问题。 - 兼容边界场景:处理无参数产品、过滤列表为空的情况,保证逻辑完整性。
- 性能优化:用
array_column和array_unique替代多层循环,更适合处理10000条级别的数据。
内容的提问来源于stack exchange,提问作者nxx
相关产品推荐
相关产品推荐

