如何以不可变风格在array_reduce迭代中传值并过滤二维数组
问题描述
给定如下二维数组:
$array = [ ['property', 'group1', 'was', 'added'], ['property', 'ouch', 'was', 'removed'], ['property', 'ouch', 'was', 'updated'], ['property', 'group3', 'was', 'added'], ['property', 'group5', 'was', 'removed'], ];
需要移除那些第二个元素(索引为1)与下一个子数组第二个元素相同的子数组,例如示例中的['property', 'ouch', 'was', 'removed']需要被移除。要求采用函数式编程实现且不允许使用突变操作。
我编写了如下代码:
function filter($arr) { $lineNumber = 0; $arrayFiltered = array_reduce($arr, function ($acc, $line) use ($arr, &$lineNumber) { if ((isset($arr[$lineNumber + 1][1])) and ($arr[$lineNumber + 1][1] !== $line[1])) { $acc[] = $line; } elseif ($lineNumber === count($arr) - 1) { $acc[] = $line; } $lineNumber++; return $acc; }, []); return $arrayFiltered; }
这段代码能实现需求,但自动化测试提示“不应使用突变操作”,涉及填充$acc和递增$lineNumber的代码行。请问如何重构代码以消除突变操作?
重构方案
要消除突变操作,核心是避免修改外部变量(比如引用传递的$lineNumber),同时让array_reduce的累加器承载必要状态,全程返回新数据结构而非修改原有内容。
方案一:基于array_reduce的纯状态流转实现
function filter($arr) { $finalState = array_reduce($arr, function ($state, $current) use ($arr) { [$filteredList, $prevKey] = $state; // 处理第一个元素,直接加入结果并更新状态 if ($prevKey === null) { return [$filteredList + [$current], $current[1]]; } // 判断当前元素是否为最后一个,或与下一个元素的标识不重复 $isLastElement = end($arr) === $current; $nextKey = isset($arr[array_search($current, $arr) + 1]) ? $arr[array_search($current, $arr) + 1][1] : null; if ($isLastElement || $current[1] !== $nextKey) { return [$filteredList + [$current], $current[1]]; } // 元素需要被移除,仅更新状态不添加到结果 return [$filteredList, $current[1]]; }, [[], null]); return $finalState[0]; }
方案二:结合array_map与array_filter的索引绑定实现
function filter($arr) { // 为每个元素绑定原始索引,避免依赖外部计数器 $indexedItems = array_map(function ($item, $index) { return ['data' => $item, 'index' => $index]; }, $arr, array_keys($arr)); // 过滤符合保留条件的元素 $filteredIndexed = array_filter($indexedItems, function ($entry) use ($arr) { $currentKey = $entry['data'][1]; $nextIndex = $entry['index'] + 1; // 最后一个元素直接保留;否则判断下一个元素的标识是否不同 return !isset($arr[$nextIndex]) || $arr[$nextIndex][1] !== $currentKey; }); // 提取出原始元素数组 return array_column($filteredIndexed, 'data'); }
重构说明
- 消除外部变量突变:两个方案都没有使用引用传递的变量,所有状态流转都通过函数返回值完成,没有修改任何外部变量。
- 纯函数式处理:所有数组操作都返回新数组(如
$filteredList + [$current]),而非直接修改原有数组结构,避免了数组突变。 - 逻辑符合需求:通过判断元素是否为最后一个、或当前元素与下一个元素的标识是否不同,精准保留需要的元素,完全匹配需求。
内容的提问来源于stack exchange,提问作者Artem Pokhiliuk
相关产品推荐
相关产品推荐

