Как смоделировать array_reverse () с помощью рекурсивной пользовательской функции? - PullRequest
4 голосов
/ 07 февраля 2020

Я хочу изменить значения в индексированном массиве с помощью рекурсии. Вывод должен быть таким же, как 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() is ссылка части массива, я прав?

Почему на мои элементы рекурсивной замены не влияют внутренние элементы?

Ответы [ 2 ]

5 голосов
/ 07 февраля 2020

Строка и массив - это две разные вещи. Я немного прояснил ваш алгоритм:

<?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);

obviously Вывод очевидно:

Array
(
    [0] => 7
    [1] => 6
    [2] => 5
    [3] => 4
    [4] => 3
    [5] => 2
    [6] => 1
)
1 голос
/ 07 февраля 2020

Если у вас включен отчет об ошибках, вы увидите три таких уведомления:

Примечание: только переменные должны передаваться по ссылке ...

Это потому, что вы передаете вывод array_slice() в качестве параметра, на который ссылаются; чтобы исправить это, вы должны объявить вывод `array_slice () как переменную перед тем, как передать его.

Тот факт, что вы видите три Уведомления, фактически указывает на то, что ваш рекурсивный метод обходится так далеко, как предполагалось, и выполняет работать, но результирующий обмен элементов не применяется к предыдущим вызовам $s - IOW все последующие рекурсивные модификации теряются. ( Демо )


@ 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 исправил это
  • no return записывается
  • -1 как 3-й параметр array_slice() имеет тот же эффект, что и ваш $len - 2.

Вот рекурсивный метод, который использует только повторные вызовы count() - без среза или объединения, потому что он передает всю исходный массив ввода каждый раз. Во время рекурсии изменяются только целевые индексы. Я меняю местами на основе приращения индекса, используя Symmetri c Разрушение массива ( инструмент, доступный от PHP7 .1 и выше ).

Код: ( Демо )

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));

Теперь ваш оригинальный фрагмент использует модификацию по ссылке, но вы явно не требуете этого в своих требованиях к вопросу - нужно использовать только рекурсию. Если вы могли бы использовать рекурсивную функцию, которая вместо этого возвращает переменную (потому что, скажем, вы хотите иметь возможность вкладывать этот вызов в другую функцию), то здесь есть один способ, который пропускает все более короткий массив с каждым уровнем рекурсии (как Ваш оригинал сделал):

Код: ( Демо )

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);
...