You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以不可变风格在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');
}

重构说明

  1. 消除外部变量突变:两个方案都没有使用引用传递的变量,所有状态流转都通过函数返回值完成,没有修改任何外部变量。
  2. 纯函数式处理:所有数组操作都返回新数组(如$filteredList + [$current]),而非直接修改原有数组结构,避免了数组突变。
  3. 逻辑符合需求:通过判断元素是否为最后一个、或当前元素与下一个元素的标识是否不同,精准保留需要的元素,完全匹配需求。

内容的提问来源于stack exchange,提问作者Artem Pokhiliuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 04:45:31