如何创建一个递归函数来取消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?
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);
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
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);