如果匹配,则递归取消设置PHP数组键。

16

我有一个数组,需要递归循环并删除任何具有键“fields”的子数组。我尝试使用数组过滤器,但我无法使其正常工作。

$myarray = array(
    'Item' => array(
        'fields' => array('id', 'name'),
        'Part' => array(
            'fields' => array('part_number', 'part_name')
        )
    ),
    'Owner' => array(
        'fields' => array('id', 'name', 'active'),
        'Company' => array(
            'fields' => array('id', 'name',),
            'Locations' => array(
                'fields' => array('id', 'name', 'address', 'zip'),
                'State' => array(
                    'fields' => array('id', 'name')
                )
            )
        )
    )    
);

这是我需要的结果:

$myarray = array(
    'Item' => array(
        'Part' => array(
        )
    ),
    'Owner' => array(
        'Company' => array(
            'Locations' => array(
                'State' => array(
                )
            )
        )
    )    
);

“remove”操作后,“Part”的值将是什么? - powtac
我只需要取消设置“fields”,并将其部分保留为“array()”。 - SonnyBurnette
11个回答

45

如果您想要递归操作,您需要将数组作为一个引用传递,否则会进行大量不必要的复制:

function recursive_unset(&$array, $unwanted_key) {
    unset($array[$unwanted_key]);
    foreach ($array as &$value) {
        if (is_array($value)) {
            recursive_unset($value, $unwanted_key);
        }
    }
}

我不确定这是否正确。根据PHP手册:如果一个按引用传递的变量在函数内部被unset(),那么只有局部变量会被销毁。调用环境中的变量将保留与unset()调用之前相同的值。http://php.net/manual/en/function.unset.php - Gerbus
@Gerbus:该语句仅适用于变量本身,而不是其(或在此情况下的数组键)。更改数组本身不会使对传递的数组的引用无效。换句话说:如果代码包含unset($array);,则您是正确的,但此代码取消设置了一个数组键。 - soulmerge

5

你需要使用array_walk函数

function remove_key(&$a) {
   if(is_array($a)) {
        unset($a['fields']);
        array_walk($a, __FUNCTION__);
   }
}
remove_key($myarray);

3
array_walk函数是否表明,如果您取消设置一个元素,该函数的行为“未定义且不可预测”? - greatwitenorth
@greatwitenorth,确实是这样说的。这可能会起作用,但很遗憾最好还是避免使用它。 - Aaron
在PHP 7中,传递引用已被弃用,因此“传递引用”不起作用。 - Sergiu Z

2

我的建议:

function removeKey(&$array, $key)
{
    if (is_array($array))
    {
        if (isset($array[$key]))
        {
            unset($array[$key]);
        }
        if (count($array) > 0)
        {
            foreach ($array as $k => $arr)
            {
                removeKey($array[$k], $key);
            }
        }
    }
}

removeKey($myarray, 'Part');

在这种情况下,isset不是最好的选择,应该使用array_key_exists null]; var_dump(isset($a['key'])); // 返回false var_dump(array_key_exists('key', $a)); // 返回true - Michał Fraś
对于偶然遇到这篇文章的人,我想提醒一下: 在使用unset之前不需要检查isset。如果变量未设置,则unset不会执行任何操作。 在使用foreach之前不需要计算数组长度。如果数组为空,foreach也不会执行任何操作。 - aProgger

2
function recursive_unset(&$array, $unwanted_key) {

    if (!is_array($array) || empty($unwanted_key)) 
         return false;

    unset($array[$unwanted_key]);

    foreach ($array as &$value) {
        if (is_array($value)) {
            recursive_unset($value, $unwanted_key);
        }
    }
}

1

代码:

$sweet = array('a' => 'apple', 'b' => 'banana');
$fruits = array('sweet' => $sweet, 'sour' => $sweet);

function recursive_array_except(&$array, $except)
{
  foreach($array as $key => $value){
    if(in_array($key, $except, true)){
      unset($array[$key]);
    }else{
      if(is_array($value)){
        recursive_array_except($array[$key], $except);
      }
    }
  }
  return;
}

recursive_array_except($fruits, array('a'));
print_r($fruits);

输入:

Array
(
    [sweet] => Array
        (
            [a] => apple
            [b] => banana
        )

    [sour] => Array
        (
            [a] => apple
            [b] => banana
        )

)

输出:

Array
(
    [sweet] => Array
        (
            [b] => banana
        )

    [sour] => Array
        (
            [b] => banana
        )

)

1
function sanitize($arr) {
    if (is_array($arr)) {
        $out = array();
        foreach ($arr as $key => $val) {
            if ($key != 'fields') {
                $out[$key] = sanitize($val);
            }
        }
    } else {
        return $arr;
    }
    return $out;
}

$myarray = sanitize($myarray);

结果:

array (
  'Item' => 
  array (
    'Part' => 
    array (
    ),
  ),
  'Owner' => 
  array (
    'Company' => 
    array (
      'Locations' => 
      array (
        'State' => 
        array (
        ),
      ),
    ),
  ),
)

1
我想到了一个简单的函数,可以基于多个键来删除多个数组元素。

点击此处查看详细示例

只需在代码中进行小小的更改。
function removeRecursive($inputArray,$delKey){
    if(is_array($inputArray)){
        $moreKey    =   explode(",",$delKey);
        foreach($moreKey as $nKey){
            unset($inputArray[$nKey]);
            foreach($inputArray as $k=>$value) {
                $inputArray[$k] = removeRecursive($value,$nKey);
            }
        }
    }
    return $inputArray;
}

$inputNew   =   removeRecursive($input,'keyOne,keyTwo');

print"<pre>";
print_r($inputNew);
print"</pre>";

1
function removeRecursive($haystack,$needle){
    if(is_array($haystack)) {
        unset($haystack[$needle]);
        foreach ($haystack as $k=>$value) {
            $haystack[$k] = removeRecursive($value,$needle);
        }
    }
    return $haystack;
}

$new = removeRecursive($old,'key');

0

试试这个函数。它将删除带有“fields”的键,只留下数组的其余部分。

function unsetFields($myarray) {
    if (isset($myarray['fields']))
        unset($myarray['fields']);
    foreach ($myarray as $key => $value)
        $myarray[$key] = unsetFields($value);
    return $myarray;
}

-1

我需要在取消数组时有更细致的控制,于是我想出了这个方法 - 使用邪恶的 eval 和其他不太正当的手段。

$post = array(); //some huge array

function array_unset(&$arr,$path){
    $str = 'unset($arr[\''.implode('\'][\'',explode('/', $path)).'\']);';
    eval($str);
}

$junk = array();
$junk[] = 'property_meta/_edit_lock';
$junk[] = 'property_terms/post_tag';
$junk[] = 'property_terms/property-type/0/term_id';
foreach($junk as $path){
    array_unset($post,$path);
}

// unset($arr['property_meta']['_edit_lock']);
// unset($arr['property_terms']['post_tag']);
// unset($arr['property_terms']['property-type']['0']['term_id']);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接