【问题标题】:Recursively delete elements of an array and their children by checking keys only通过仅检查键递归删除数组的元素及其子元素
【发布时间】:2016-01-12 10:10:50
【问题描述】:

我正在寻找一种通过仅检查键来递归删除数组部分以及这些部分的子项的方法。

在下面的示例中,$array 是输入数组,$remove 包含应该从 $array 中删除的键:

$array = [
    'key1' => [
        'key11' => [],
        'key12' => [
            'key121' => [],
            'key122' => [],
            'key123' => [],
        ],
        'key13' => [],
    ],
    'key2' => [
        'key21' => [],
        'key22' => [],
        'key23' => [],
        'key24' => [],
        'key25' => [
            'key251' => [
                'key2511' => [],
                'key2512' => [],
                'key2513' => [],
                'key2514' => [],
                'key2515' => [],
            ],
            'key252' => [
                'key2521' => [],
                'key2522' => [],
                'key2523' => [],
                'key2524' => [],
                'key2525' => [],
            ],

        ],
    ],
    'key3' => [
        'key31' => [],
        'key32' => [],
        'key33' => [],
        'key34' => [],
        'key35' => [
            'key351' => [
                'key3511' => [],
                'key3512' => [],
                'key3513' => [],
                'key3514' => [],
                'key3515' => [],

            ],
        ],
    ],
];

$remove = [
    'key1' => [
        'key12' => [
            'key121' => [],
        ],
        'key13' => [],
    ],
    'key2' => [
        'key25' => [
            'key251' => [
                'key2514' => [
                ],
            ],
            'key252' => [],
        ],
    ],
    'key3' => [],
];

我写了一个丑陋的非递归算法:

foreach ($array as $k1 => $v1) {
    foreach ($v1 as $k2 => $v2) {
        foreach ($v2 as $k3 => $v3) {
            foreach ($v3 as $k4 => $v4) {
                if (isset($array[$k1][$k2][$k3][$k4]) && isset($remove[$k1][$k2][$k3][$k4]) && 0 === count($remove[$k1][$k2][$k3][$k4])) {
                    unset($array[$k1][$k2][$k3][$k4]);
                }
            }
            if (isset($array[$k1][$k2][$k3]) && isset($remove[$k1][$k2][$k3]) && 0 === count($remove[$k1][$k2][$k3])) {
                unset($array[$k1][$k2][$k3]);
            }
        }
        if (isset($array[$k1][$k2]) && isset($remove[$k1][$k2]) && 0 === count($remove[$k1][$k2])) {
            unset($array[$k1][$k2]);
        }
    }
    if (isset($array[$k1]) && isset($remove[$k1]) && 0 === count($remove[$k1])) {
        unset($array[$k1]);
    }
}

var_dump($array);

它返回我正在寻找的输出:

array(2) {
  ["key1"]=>
  array(2) {
    ["key11"]=>
    array(0) {
    }
    ["key12"]=>
    array(2) {
      ["key122"]=>
      array(0) {
      }
      ["key123"]=>
      array(0) {
      }
    }
  }
  ["key2"]=>
  array(5) {
    ["key21"]=>
    array(0) {
    }
    ["key22"]=>
    array(0) {
    }
    ["key23"]=>
    array(0) {
    }
    ["key24"]=>
    array(0) {
    }
    ["key25"]=>
    array(1) {
      ["key251"]=>
      array(4) {
        ["key2511"]=>
        array(0) {
        }
        ["key2512"]=>
        array(0) {
        }
        ["key2513"]=>
        array(0) {
        }
        ["key2515"]=>
        array(0) {
        }
      }
    }
  }
}

我的问题是,我怎样才能使这个功能递归,理论上,$array 可以无限嵌套?

我们将不胜感激地接受任何帮助。谢谢!


与此同时,我想出了一个替代解决方案:

function array_remove_key_recursive($input, $remove)
{
    $ret = [];

    foreach ($input as $key => $value) {
        if (array_key_exists($key, $remove)) {
            if (is_array($value)) {
                if (count($remove[$key]) > 0) {
                    $diff_recursive = array_remove_key_recursive($value, $remove[$key]);
                    if (count($diff_recursive) > 0) {
                        $ret[$key] = $diff_recursive;
                    }
                }
            } else {
                if ($value != $remove[$key]) {
                    $ret[$key] = $value;
                }
            }
        } else {
            $ret[$key] = $value;
        }
    }

    return $ret;
}

【问题讨论】:

  • 将所有解释您的问题的代码添加到您的问题中
  • 按要求将代码添加到问题中。

标签: php arrays recursion diff


【解决方案1】:

我会这样做

function test (&$arr, $remove) {
    $keys =array_keys ($remove, [], true) ;
    $arr =array_filter ($arr, function ($v, $k) use ($remove, $keys) {
            return !in_array ($k, $keys, true) ; 
        },
        ARRAY_FILTER_USE_BOTH            
    ) ;
    $keys =array_diff (array_keys ($remove), $keys) ;
    foreach ( $keys as $key )
        test ($arr [$key], $remove [$key]) ;
}

test ($array, $remove) ;
print_r ($array) ;

【讨论】:

  • 感谢您的回答。我测试了它,它按预期工作。
【解决方案2】:

这是一个递归地做你需要的函数。

function remove_by_keys(array $array, array $remove)
{
    // Copy the input array into the result; will remove parts of it
    // according to the information stored in $remove
    $result = $array;

    // Check the keys to remove
    foreach ($remove as $key => $value) {
        if ($value === []) {
            // Remove the key and the entire value associated with the key
            unset($result[$key]);
        } else {
            // Keep the key, recursively remove parts of the value (next level)
            $result[$key] = remove_by_keys($array[$key], $remove[$key]);
        }
    }

    return $result;
}

工作原理:

该函数接收两个参数:$array 是输入数组,$remove 是要从 $array 中删除的键(和子键)列表。

它会复制输入数组,然后分析键 ($key) 和 $remove 的值。如果值为[](空数组),则从结果中完全删除$array 的相应键和值。如果$remove[$key] 不是[],那么函数会递归调用$array[$key]$remove[$key](下一级),并且它返回的值(过滤后的$array[$key])存储在结果数组中的键@987654334 @。

【讨论】:

  • 感谢您的解决方案。它优雅简单。我最喜欢的解决方案!
猜你喜欢
  • 2019-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-23
  • 2012-04-11
相关资源
最近更新 更多