通过仅检查键递归删除数组的元素及其子元素

时间:2016-01-12 10:10:51

标签: php arrays recursion diff

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

在下面的示例中,$ 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;
}

2 个答案:

答案 0 :(得分:2)

我将如何做到这一点

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

答案 1 :(得分:1)

这是一个递归地执行您需要的功能。

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])存储在键$key的结果数组中。