dotdx80642
dotdx80642
2018-01-12 15:18

如何创建一个递归函数来取消PHP中的多维数组?

Below is my target array which I would like to unset its elements by key based on the candidate array element.

$target = [
    60 => "Home"
    "Villa" => [
        "30" => "Vi",
    ],
    70 => "A",
    40 => "B",
    50 => "C",
    "Land" => [
        1 => "La",
        35 => "Lb",
        37 => "Lc",
        39 => "Ld",
    ],
];

$candidate = [30, 50, 35, 37];

Below is the result that I want after unsetting.

$target = [
    60 => "Home"
    70 => "A",
    40 => "B",
    "Land" => [
        1 => "La",
        39 => "Ld",
    ],
];

'Villa' must also be gone because it's empty after it's element "30" => "Vi" has been unset.

Below my solution in for-loop.

foreach ($target as $id => $option) {
    if (isset($candidate[$id])) {
      unset($target[$id]);
    }
    elseif (is_array($option)) {
      foreach ($option as $sub_id => $opt) {
        if (isset($candidate[$sub_id])) {
          unset($target[$id][$sub_id]);
        }
      }
    }

    if (!count($target[$id])) {
      unset($target[$id]);
    }
}

How can I replace this for-loop in a recursive solution?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

3条回答

  • dqrsceg6279196 dqrsceg6279196 3年前
    function del($target, $candidate) {
        foreach ($target as $key => $value) {
            if (in_array($key, $candidate)) {
                unset($target[$key]);
            } elseif (is_array($value)) {
                $target[$key] = del($value, $candidate);
                if (!count($target[$key])) {
                    unset($target[$key]);
                }
            }
        }
        return $target;
    }
    
    $new = del($target, $candidate);
    var_dump($new);
    
    点赞 评论 复制链接分享
  • douyuliu9527 douyuliu9527 3年前

    EDIT:

    <?php
    $target = [
        60 => "Home",
        "Villa" => [
            "30" => "Vi",
        ],
        70 => "A",
        40 => "B",
        50 => "C",
        "Land" => [
            1 => "La",
            35 => "Lb",
            37 => "Lc",
            39 => "Ld",
        ],
    ];
    
    $candidate = [30, 50, 35, 37];
    
    function clean(&$target, $candidate){
        // Loop through target
        foreach($target as $index => $value){
            // If the value is an array
            if(is_array($value)){
                // Clean it first
                $result = clean($value, $candidate);
                $target[$index] = $result;
            } else {
                // Check if the key is in the candidate array
                if(in_array($index, $candidate)){
                    $target[$index] = NULL;
                }
            }
            // If the value is empty
            if(empty($target[$index])){
                // Unset it
                unset($target[$index]);
            }
        }
    }
    
    $target = clean($target, $candidate);
    
    var_dump($target);
    

    Result:

    /var/www/test.php:47:
    array (size=4)
      60 => string 'Home' (length=4)
      70 => string 'A' (length=1)
      40 => string 'B' (length=1)
      'Land' => 
        array (size=2)
          1 => string 'La' (length=2)
          39 => string 'Ld' (length=2)
    

    As symcbean mentioned using reference here would be better

    点赞 评论 复制链接分享
  • douxie9471 douxie9471 3年前

    This started as a comment on Mehdi's answer, but I ran out of space:

    While I believe arrays are passed by reference, and there should be minimal overhead assigning the reference to the variable it came from, it strikes me that explicitly passing by reference might be more robust and transparent.

    i.e.

    function clean(&$target, $candidate, $depth=0){
       if (++$depth>10) {
          // erk!
          trigger_error("Too deep!");
       }
       // Loop through candidates
       foreach($candidate as $index){
           // If the value is an array
           if(isset($target[$index]) && is_array($target[$index])){
               clean($target[$index], $candidate, $depth);
               if (!count($target[$index])) unset($target[$index]); // thanks jhilgeman
           } else {
               isset($target[$index]) && unset($target[$index]);
           }
       }
    }
    
    clean($target, $candidate);
    var_dump($target);
    
    点赞 评论 复制链接分享