如何使用递归用户定义函数模拟 array_reverse()?

Posted

技术标签:

【中文标题】如何使用递归用户定义函数模拟 array_reverse()?【英文标题】:How to simulate array_reverse() using a recursive user-defined function? 【发布时间】:2020-05-23 13:37:30 【问题描述】:

我想使用递归来反转索引数组中的值。输出应与array_reverse() 相同。

我的代码:

$array = [1,2,3,4,5,6,7];

function reverseString(&$s) 
    if(count($s) < 2)
        return;
    
    $len = count($s);
    $temp = $s[0];
    $s[0] = $s[$len - 1];
    $s[$len - 1] = $temp;
    reverseString(array_slice($s, 1, $len - 2));


reverseString($array);
print_r($array);

返回:

Array (
    [0] => 7
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => 1 )

array_slice() 是数组部分的链接,对吗?

为什么我的递归交换技术不会影响内部元素?

【问题讨论】:

array_reverse() 应该是array_slice(...),而不是$array_slice(...)。它是一个函数,而不是一个变量。 不太清楚你想在这里问什么。但是$array_slice 应该是array_slice 开头的,你不想在这里使用“变量函数”。 php 并没有为此优化。考虑如何在 PHP 中以更具功能性的编程风格进行编码可能会很有趣,但请不要以人们将使用的任何方式编写此代码。 【参考方案1】:

字符串和数组是两个不同的东西。我稍微清理了你的算法:

<?php
$array = [1,2,3,4,5,6,7];

function reverseSequence(&$s) 
    $len = count($s);
    if($len < 2)
        return;
    

    $rest = array_slice($s, 1, $len - 2);
    reverseSequence($rest);
    $s = array_merge([$s[$len - 1]], $rest, [$s[0]]);


reverseSequence($array);
print_r($array);

输出显然是:

Array
(
    [0] => 7
    [1] => 6
    [2] => 5
    [3] => 4
    [4] => 3
    [5] => 2
    [6] => 1
)

【讨论】:

【参考方案2】:

如果您打开了错误报告,您将看到以下三个通知:

注意:只能通过引用传递变量...

这是因为您将array_slice() 的输出作为引用参数传递;要解决此问题,您必须在传入 `array_slice() 的输出之前将其声明为变量。

您看到三个通知的事实实际上表明您的递归技术已按预期遍历并完成工作,但结果元素交换并未应用于$s 上的先前调用——IOW 所有随后的递归修改将丢失。 (Demo)


@arkascha 比我早一个小时为你的脚本提供了必要的修复,但我可能会稍微不同。

代码:(演示)

function swapOutermost(&$a) 
    $size = count($a);
    if ($size > 1) 
        $innerElements = array_slice($a, 1, -1);
        swapOutermost($innerElements);
        $a = array_merge(
            [$a[$size - 1]],  // last is put first
            $innerElements,   // recursed reference in the middle
            [$a[0]]           // first is put last
        );
    

count() 每次递归调用只有一次 -- arkascha 解决了这个问题 没有写return -1 作为array_slice() 的第三个参数与您的$len - 2 的效果相同。

这是一种递归技术,它只使用迭代的count() 调用——没有切片或合并,因为它每次都传递整个原始输入数组。只有目标索引在递归期间发生变化。我正在使用Symmetric Array Destructuring (a tool available from PHP7.1 and up) 基于索引增量进行交换。

代码:(Demo)

function swapOutermost(&$a, $i = 0) 
    $last = count($a) - 1 - $i;
    if ($i < $last) 
        [$a[$i], $a[$last]] = [$a[$last], $a[$i]];
        swapOutermost($a, ++$i);
    


swapOutermost($array);

...当然,由于计数永远不会改变,因此只传递一次并重用它会更有效。

function swapOutermost(&$a, $count, $i = 0) 
    $last = $count - 1 - $i;
    if ($i < $last) 
        [$a[$i], $a[$last]] = [$a[$last], $a[$i]];
        swapOutermost($a, $count, ++$i);
    


swapOutermost($array, count($array));

现在,您原来的 sn-p 使用引用修改,但您没有在问题要求中明确要求这一点 - 只是必须使用递归。如果您可能会接受一个返回变量的递归函数(因为,比如说,您希望能够将此调用嵌套在另一个函数中),那么这里有一种方法可以通过每个递归级别传递一个更短的数组(如你原来的):

代码:(Demo)

function recursiveArrayReverse($a) 
    $size = count($a);
    if ($size < 2) 
        return $a;
    
    return array_merge(
        [$a[$size - 1]],
        recursiveArrayReverse(
            array_slice($a, 1, -1)
        ),
        [$a[0]]
    );


$array = [1, 2, 3, 4, 5, 6, 7];
$array = recursiveArrayReverse($array);

【讨论】:

以上是关于如何使用递归用户定义函数模拟 array_reverse()?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用降雪导出预定义函数?

递归简论

如何创建参数化递归 CTE 以展平标量函数中的层次结构?

如何在 xpath 表达式中实现具有名称的用户定义函数?

C语言详解:函数递归专题

UE4定义递归函数