【问题标题】:How to unset elements using array_walk_recursive如何使用 array_walk_recursive 取消设置元素
【发布时间】:2011-09-08 07:38:23
【问题描述】:

我需要从嵌套到另一个数组中的数组中取消设置元素,从而只保留第一个 N 元素(N 是预定义的)。只有具有数字索引的元素才会受到影响。

输入数组:

Array
(
    [0] => Array (
        [a] => 'w'
        [b] => Array (
             [0]=> 'x'
             [1]=> 'x'
             [2]=> 'x'
        )
    )               
    [1] => Array (
        [a] => 'y'
    )
    [2] => Array (
        [0] => 'z'
        [1] => 'z'
        [2] => 'z'
    )
)

所需的输出(N=2):

Array
(
    [0] => Array (
        [a] => 'w'
        [b] => Array (
             [0]=> 'x'
             [1]=> 'x'
        )
    )               
    [1] => Array (
        [a] => 'y'
    )
)

根据上述定义,只有 [0][b][2][2] 未设置,因为它们具有数字索引,并且它们都表示各自数组的第三个元素。

【问题讨论】:

  • 您希望如何嵌套它们?我是否正确假设可能有 10 层嵌套?还是您的示例也是最大嵌套量?也许给出一个具体的例子来说明它的作用可以为你的代码提供一个清晰的图像。
  • 嵌套层级没有任何限制。可能有 10 个级别,可能更多,可能更少,因此我最初的印象是我可能必须使用array_walk_recursive 来完成这项工作,但等待更多反馈以防有更好的方法来做。

标签: php arrays recursion multidimensional-array


【解决方案1】:

尚未测试,但类似的方法可能有效。

function myFunc(&$array){
foreach($array as $key=>&$value){
 if(is_array($value)){
   myFunc($value);
 }
 if(is_numeric($key) && $key > 1){
   unset($array[$key]);
 }
}
}

关于array_walk。 php.net 说:

程序员不能添加、取消设置或 重新排序元素。如果回调确实 不尊重这一要求, 这个函数的行为是 未定义且不可预测。

【讨论】:

  • 这看起来很适合取消设置特定数组的元素。现在我需要找到一种方法来递归地获取数组的所有嵌套数组。
  • 我写的函数是递归的。如果一个值是一个函数,它会递归调用自身。
【解决方案2】:

为自己编写一个完全符合您要求的函数。然后记录该函数,以便如果您需要在大约两周内使用它,您可能想知道该函数到底在做什么。

我这样说是因为您要处理的数据结构似乎非常具体。因此,值得将其单独封装在一个函数中以隐藏复杂性。正确命名函数。

在函数内部,您可以根据需要制定的各种条件以各种方式处理数据。来自外部的参数可以作为函数参数传递。返回值就是你想要达到的结果。

【讨论】:

    【解决方案3】:

    这对我有用,可能不是最干净的代码。

    $array = array
    (
        array(
            'a' => 'w',
            'b' => array('x','x','x')
        ),
        array(
            'a' => 'y'
        ),
        array(
            'z','z','z'
        )
    );
    
    function recurse_and_strip ($array, &$size=2)
    {
        foreach ($array as $key => &$element)
        {
            if (is_hash($element))
            {
                $element = recurse_and_strip($element,$size);
            } else if (is_array($element))
            {
                $deletefrom = false;
                // now the tricky part.. see how many must be deleted
                for ($i=0; $i < count($element); $i++ )
                {
                    if ($size == 0)
                    {
                        echo "Delete from " . $i;
                        $deletefrom = $i;
                        break 1;
                    }
                    $size--;
                }
                if ($deletefrom !== false)
                {
                    if ($deletefrom == 0)
                    {
                        unset($array[$key]);
                    } else {
                        array_splice($element,$deletefrom);
                    }
                }
            }
        }
        return $array;
    }
    
    // source http://www.benjaminkeen.com/?p=23
    function is_hash($var)
    {
      if (!is_array($var))
        return false;
    
      return array_keys($var) !== range(0,sizeof($var)-1);
    }
    
    var_dump(recurse_and_strip($array,2));
    

    【讨论】:

    • 对我有用,尽管我认为您的 var_dump 行不正确,因为 2 是作为 var_dump 的参数而不是 recurse_and_strip 的参数。还是非常感谢。
    • 不幸的是,在具有 3 个嵌套级别的数组上进行测试时,它不再起作用了。
    • 你能告诉我你正在使用的例子吗?在这里它也适用于 3 个嵌套级别。还有,有什么错误?
    【解决方案4】:

    array_walk_recursive 本身无法实现你想要的。即使您可以通过引用传递数组,但在回调中取消设置变量只会在该范围内取消设置。

    不过,你可以使用walk_recursive_remove函数:

    /**
     * http://uk1.php.net/array_walk_recursive implementation that is used to remove nodes from the array.
     *
     * @param array The input array.
     * @param callable $callback Function must return boolean value indicating whether to remove the node.
     * @return array
     */
    function walk_recursive_remove (array $array, callable $callback) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                $array[$k] = walk_recursive_remove($v, $callback);
            } else {
                if ($callback($v, $k)) {
                    unset($array[$k]);
                }
            }
        }
    
        return $array;
    }
    

    您需要使用$callback 实现自己的逻辑来取消设置特定值。

    【讨论】:

      【解决方案5】:

      这里有一个更通用的解决方案来修改叶子所属的数组。您可以取消设置当前键,或添加兄弟等。

      /**
       * Modified version of array_walk_recursive that passes in the array to the callback
       * The callback can modify the array or value by specifying a reference for the parameter.
       *
       * @param array The input array.
       * @param callable $callback($value, $key, $array)
       */
      function array_walk_recursive_array(array &$array, callable $callback) {
          foreach ($array as $k => &$v) {
              if (is_array($v)) {
                  array_walk_recursive_array($v, $callback);
              } else {
                  $callback($v, $k, $array);
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-21
        • 2010-10-04
        • 2019-08-27
        • 1970-01-01
        • 2021-05-29
        • 2011-11-02
        • 2016-10-01
        相关资源
        最近更新 更多