phpimmutabilityarray-reduce

how to use array_reduce in immutable style?


I have been going through online study on a resource I quite liked till this very moment. The problem is they want my perfectly working array_reduce function is written "in immutable style". Which means that nothing should mutate inside, even accumulator. Which seems to me like making no sense. So, here is a piece of code I use in that study project they do not want to accept, function for flattening an array:

function flatten(array $tree)
{
    $result = array_reduce($tree, function ($acc, $item) {
        $newValue = is_array($item) ? flatten($item) : $item;
        if (!is_array($newValue)) {
            $acc[] = $newValue;
        } else {
            $acc = array_merge($acc, $newValue);
        }
        return $acc;
    }, []);
    return $result;
}

It works perfectly but this resourse (not free, BTW) does not accept it with notices "Should not use of mutating operators" to the lines where I change $acc.

So I ask them WTF and they answer me: do not change input argument and make a new acc instead and return this new acc from the callback. So I rewrite like this:

function flatten(array $tree)
{
    $result = array_reduce($tree, function ($acc, $item) {
        $accNew = $acc;
        $newValue = is_array($item) ? flatten($item) : $item;
        if (!is_array($newValue)) {
            $accNew[] = $newValue;
        } else {
            $accNew = array_merge($acc, $newValue);
        }
        return $accNew;
    }, []);
    return $result;
}

But this doesn't help, the same "Should not use of mutating operators" notices for the lines where now $accNew is being changed.

What the hell? I'm completely confused. Does this even make sense? Is this an appropriate demand? 'Cause I googled on it and it seems there are pretty much no people on Internet who were interested in using array_reduce "in immutable style"...


Solution

  • I'm not 100% certain how this code gets used, but I think you might even be able to skip writing to the accumulator or a copy of it completely, and just return instead:

    function flatten(array $tree): array
    {
        return array_reduce(
            $tree,
            static function ($acc, $item) {
                $newValue = is_array($item) ? flatten($item) : $item;
                return array_merge($acc, is_array($newValue) ? $newValue : [$newValue]);
            },
            []
        );
    }
    

    Edit: My previous answer didn’t account for previous items in the accumulator, this does.