dongruo0909
2019-05-10 11:59
浏览 197
已采纳

按键递归删除嵌套数组中的元素(array_filter_recursive)

I want to be able to remove elements from the multidimentianal array by key

Example of such an array can be:

Array
(
    [data] => Array
        (
            [todo] => code review
            [schedule] => Array
                (
                    [endDate] => 2019-05-10T00:00:00+01:00
                    [startDate] => 2019-05-09T00:00:00+01:00
                )

            [codeDetails] => Array
                (
                    [language] => PHP
                    [type] => class
                    [abstract] => true
                    [methodCount] => Array
                        (
                            [public] => 3
                            [protected] =>
                            [private] => 1
                        )

                    [LOC] => 123
                    [cyclomaticComplexity] => 4
                    [author] => Array (
                            [name] => Lukasz
                            [email] => private@tulik.io
                        )
                )

        )
)

I have two methods, recursiveArrayDelete removes any elements where the callback returns true:

private function recursiveArrayDelete(array &$array, callable $callback): array
{
    foreach ($array as $key => &$value) {
        if (is_array($value)) {
            $value = $this->recursiveArrayDelete($value, $callback);
        }
        if ($callback($value, $key)) {
            unset($array[$key]);
        }
    }

    return $array;
}

Second, removes properties all included in restrictedProperties from the array:

private function sanitizedArray(array &$array, array &$restrictedProperties): array
{
    foreach ($restrictedProperties as $restrictedProperty) {
        $this->recursiveArrayDelete(
            $array,
             static function () use ($array, $restrictedProperty): bool {
                array_walk_recursive(
                    $array,
                    static function ($value, $key) use (&$bool, $restrictedProperty) {
                         // here $bool is as expected from condition
                         $bool = $key === $restrictedProperty;
                     });
                  // here is alwalys false
                 return $bool; 
             });
    }

    return $array;
}

Example of usage:

$this->sanitizedResponse($data, ['methodCount', `endDate`]);

Should remove these elements from array. But as I mentioned in commenrt sanitizedArray where return $bool; always result in false

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • doujiang3997 2019-05-10 14:11
    已采纳

    @dWinder's answer is almost perfect. But when I played around with it a bit more I noticed that it would not delete an array under a given "restricted property".

    Let us assume that all "D"-elements were to be removed:

    dWinder's solution would result in:

    Array
    (
        [A] => aa
        [B] => Array
            (
                [A] => aaa
                [B] => bb
            )
    
        [C] => cc
        [D] => Array
            (
                [E] => ee
            )
    
    )
    

    The array under "D" is still there. But when you switch the if condition and action with that of the else if you get the (assumed!) desired result:

    Array
    (
        [A] => aa
        [B] => Array
            (
                [A] => aaa
                [B] => bb
            )
    
        [C] => cc
    )
    

    So, the improved function code should look something like this (I am quoting parts of @dWinder's solution here):

    $arr = array("A" => "aa", "B" => ["A" => "aaa", "B" => "bb"], "C" => "cc", "D" => ["E" =>"ee"]);
    
    function array_filter_recursive(array &$array, callable $callback) {
        foreach ($array as $key => &$value) {
            if ($callback($key, $value))   unset($array[$key]);
            else if (is_array($value))     array_filter_recursive($value, $callback);
        }
    }
    
    function sanitizedArray(&$arr, $restrictedProperties) {
        foreach($restrictedProperties as $prop) {
            array_filter_recursive($arr, function($k, $v) use ($prop) {return $prop == $k;});
        }
    }
    sanitizedArray($arr, ["D"]);
    print_r($arr);
    

    See here for a demo: https://3v4l.org/05tc7

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • doujiang1993 2019-05-10 13:24

    You done very well. Notice you have 2 issues: first you doing the recursion in both function and you reassign to $bool - so only the last compare is the one that count (this is why you getting false all the time).

    I would make your code more simpler this way:

    function array_filter_recursive(array &$array, callable $callback) {
        foreach ($array as $key => &$value) {
            if ($callback($key, $value)) unset($array[$key]);
            else if (is_array($value)) array_filter_recursive($value, $callback);
        }
    }
    
    function sanitizedArray(&$arr, $restricted, $keys = false) {
        foreach($restricted as $val) {
            array_filter_recursive($arr, function($k, $v) use ($val, $keys) {return $keys ? ($val === $k) : ($val === $v);});
        }
    }
    

    Now you can simply use it as your example: $this->sanitizedResponse($data, ['methodCount', 'endDate'], true);

    Here is live example with fake data: 3v4l

    评论
    解决 无用
    打赏 举报