array_walk_recursive与数组?

时间:2014-07-03 12:30:29

标签: php arrays recursion

我有一个菜单数组,它是一个多维数组,我想对每个项目做一些事情,所以我尝试了array_walk_recursive。这是菜单:

$menu = array(
    array(
        'name'=>'a',
        'url'=>'b',
    ),
    array(
        'name'=>'c',
        'url'=>'d',
        'children'=>array(
            array(
                'name'=>'e',
                'url'=>'f'
            )
        )
    )
);

但是array_walk_recursive只让我处理每一个元素,而不是数组。

array_walk_recursive($menu, function(&$item){
    var_dump($item);//return a;b;c;d;e;f;g
});

我想要的是这样的:

array_walk_recursive_with_array($menu, function(&$item){
    var_dump($item);//return array('name'=>'a','url'=>'b');a;b;array('name'=>'c',...);c;d;...
    if(is_array($item) && isset($item['name'])){
        // I want to do something with the item.
    }
})

是否有任何PHP本机功能实现?

3 个答案:

答案 0 :(得分:0)

根据array_walk_recursive documentation,你无法得到内部数组键。 实现需求的一种方法是使用array_walk并创建自己的递归。

function HandleArray(&$value){
    if(is_array($value)){
        //Do something with all array
        array_walk($value,'HandleArray');
    }
    else{
       //do something with your scalar value
    }
}
array_walk(array($your_array),'HandleArray');

答案 1 :(得分:0)

@artragis 示例中使用 array_walk() 的无限递归保护似乎是必要的。 一个 ArrayHelper 类示例,用于将给定数组减少为给定数组键的数组值:

class ArrayHelper {
    /**
     * arrayFlattenToKeyValues - Like finding keys with array_walk_recursive()
     *   without the restriction "Any key that holds an array will not be passed to the function"
     * @see https://www.php.net/manual/en/function.array-walk-recursive.php#refsect1-function.array-walk-recursive-examples
     * @param array $deepArray
     * @param string $fromKey
     * @param int $maxDepth default = 10
     * @param array $accumulator default = []
     *
     * @return array
     */
    public static function arrayFlattenToKeyValues(
        array $deepArray,
        string $fromKey,
        int $maxDepth = 10,
        array $accumulator = []
    ): array {
        array_walk($deepArray, function ($value, $key) use (&$accumulator, $fromKey, $maxDepth) {
            if ($key === $fromKey) {
                $accumulator[] = $value;
            }
            if ($maxDepth > 0 && is_array($value)) {
                $accumulator = self::arrayFlattenToKeyValues($value, $fromKey, $maxDepth - 1, $accumulator);
            }
        });

        return $accumulator;
    }
}

这可能可以改进、简化或以不同的方式完成;请做!

答案 2 :(得分:-2)

这是一个基本的实用程序,递归自定义函数:

代码:(Demo

function recurseAll($node) {
    echo "\n---\n";
    if (is_iterable($node)) {
        var_export($node);
        foreach ($node as $childNode) {
            recurseAll($childNode);
        }
    } else {
        echo $node;
    }
}

array_walk($array, 'recurseAll');
// array_walk() avoids printing the entire parent array to screen as the first element

输出:

---
array (
  'name' => 'a',
  'url' => 'b',
)
---
a
---
b
---
array (
  'name' => 'c',
  'url' => 'd',
  'children' => 
  array (
    0 => 
    array (
      'name' => 'e',
      'url' => 'f',
    ),
  ),
)
---
c
---
d
---
array (
  0 => 
  array (
    'name' => 'e',
    'url' => 'f',
  ),
)
---
array (
  'name' => 'e',
  'url' => 'f',
)
---
e
---
f

为弄清楚artragis的答案可能是什么,... array_walk_recursive()确实提供了对键和值的访问,但是仅在给定值是“标量”(非-迭代)。手册将这些标量值称为“叶节点”。

对于那些不熟悉本机php函数的人来说,另一个重要的注意事项是,尽管它保持键-值关联,但实际上并没有深度。换句话说,您将无法unset()元素,也无法区分当前元素所在的当前级别。

我的代码段将打印所有可迭代和不可迭代的数据,优先级是在继续迭代当前级别之前更深地递归。

我不确定您要如何使用name元素,但是以下调整后的代码段将向您展示如何通过引用修改数组(注意&的两种用法)。

代码:(Demo

function recurseAll(&$node, $key) {
    if (is_iterable($node)) {
        foreach ($node as $key => &$childNode) {
            recurseAll($childNode, $key);
        }
    } elseif ($key === "name") {
        $node = "***{$node}***";
    }
}


array_walk($array, 'recurseAll');  // or just call : recurseAll($array, null);
echo "After modified by reference:\n";
var_export($array);

输出:

After modified by reference:
array (
  0 => 
  array (
    'name' => '***a***',
    'url' => 'b',
  ),
  1 => 
  array (
    'name' => '***c***',
    'url' => 'd',
    'children' => 
    array (
      0 => 
      array (
        'name' => '***e***',
        'url' => 'f',
      ),
    ),
  ),
)