如何让array_walk_recursive访问每个节点?

时间:2016-03-02 10:29:20

标签: php recursion

我有一个需要修改的递归$data结构。考虑$item的每个节点都应该获得一个值为$value的属性。我尝试的事情(以及它们如何失败)是:

  • array_walk_recursive:仅访问叶节点。
  • 堆栈/队列:我无法修改原始结构,但只更改了堆栈/队列上的副本。
  • 循环:如果没有堆栈/队列方法,我需要知道嵌套级别并编写大量嵌套循环。
  • array_map:我没有写出适当的递归回调,因为$value的值不是静态的,而是先前代码的结果。所以它必须以某种方式“进入”回调。由于use仅适用于匿名函数,因此我无法编写递归函数。
  • 循环和递归函数:This answer对类似问题失败的原因与array_map方法相同。

我在代码中的情况与此示例类似:

<?php

$value = 'example';

$data = array(
    'foo' => 'bar'
    'items' => array(
        array(
            'foo' => 'bar',
            'items' => array(
                array('foo' => 'bar')
            )
        )
    )
);

// do this recursively to every member of an 'items' property:
$item['baz'] = $value;

你能想出一个不同的方法,还是帮助我理顺到目前为止失败的那个方法?

更新

我试过的一些代码不起作用:

// Parse error:  syntax error, unexpected 'use' (T_USE), expecting '{'

function do (&$item) use ($value) {

    $item['baz'] = $value;

    foreach ($item['items'] as $next) {

        do($next);
    }
}

// Undefined variable: value

function do (&$item) {

    $item['baz'] = $value;

    foreach ($item['items'] as $next) {

        do($next);
    }
}

foreach ($data['items'] as $item) {

    do($item);
}

现在可以使用(我希望不必传递$value参数):

function do (&$item, $value) {

    $item['baz'] = $value;

    foreach ($item['items'] as &$next) {

        do($next, $value);
    }
}

foreach ($data['items'] as &$item) {

    do($item, $value);
}

3 个答案:

答案 0 :(得分:0)

Check this code for get each key and value:

<?php

error_reporting(0);

$value = 'example';

$data = array(
    'foo' => 'bar',
    'items' => array( array( 'foo' => 'bar','items' => array(array('foo' => 'bar') ) ) )
);


$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($data));
  foreach ($iterator as $k => $v) {
        echo $k.'=>'.$v;
        echo '</br>';
  }

?>

Formatting was necessary but did not suffice for the minimum edit length. So I added this otherwise useless text.

答案 1 :(得分:0)

以下递归函数适用于我。请注意,它还需要在foreach循环内通过引用传递参数:

$value = 'example';

function do (&$item, $value) {

    $item['baz'] = $value;

    foreach ($item['items'] as &$next) {

        do($next, $value);
    }
}

foreach ($data['items'] as &$item) {

    do($item, $value);
}

答案 2 :(得分:0)

我使用这种方法:

<?php

/**
 * @param array $arr
 * @param callable $callback
 * @param array $options
 *
 *
 * Example:
 * (this will add the link property to every node in the array recursively)
 *
 *
 * $linkFmt = "/mylink/{type}/{slug}";
 * ArrayTool::updateNodeRecursive($ret, function (array &$row) use ($linkFmt) {
 *      $row['link'] = str_replace([
 *          "{type}",
 *          "{slug}",
 *      ], [
 *          $row['type'],
 *          $row['slug'],
 *          ], $linkFmt);
 * });
 *
 *
 *
 *
 */
public static function updateNodeRecursive(array &$arr, callable $callback, array $options = [])
{
    $childrenKey = $options['childrenKey'] ?? "children";
    foreach ($arr as $k => $v) {
        call_user_func_array($callback, [&$v]);

        if (array_key_exists($childrenKey, $v) && $v[$childrenKey]) {
            $children = $v[$childrenKey];
            self::updateNodeRecursive($children, $callback, $options);
            $v[$childrenKey] = $children;
        }
        $arr[$k] = $v;
    }
}