I have a multidimensional array as a result from a webservice called from PHP. I cannot edit the webservice, but the result is as
array (size=5)
'id' => int 0
'name' =>
array (size=7)
'it' => string 'Tutti' (length=5)
'ca' => string 'Tots' (length=4)
'es' => string 'Todos' (length=5)
'de' => string 'Alle' (length=4)
'fr' => string 'Tous' (length=4)
'nl' => string 'Alle' (length=4)
'en' => string 'All' (length=3)
'tree' =>
array (size=0)
empty
'languages' =>
array (size=7)
'subTypes' =>
array (size=4)
0 =>
array (size=5)
'id' => int 1
'name' =>
array (size=29)
...
'tree' =>
array (size=1)
...
'languages' =>
array (size=29)
...
'subTypes' =>
array (size=3)
...
1 =>
array (size=5)
'id' => int 2
'name' =>
array (size=29)
...
'tree' =>
array (size=1)
...
'languages' =>
array (size=29)
...
'subTypes' =>
array (size=6)
...
As you can see, you can interpret it as a multidimensional array of objects. Each objects can have child objects of same type.
My goal is to get only the elements on a specific language, fe en
(and thus rest is not taken). I thought to use a recursive function.
// filter array
function getByKey($array, $search, $level, $valuesUsed) {
echo '<ul>';
foreach($array as $key => $value) {
if(is_array($array[$key])) {
$valuesUsed = getByKey($array[$key], $search, $level + 1, $valuesUsed);
} else if ($key === $search) {
if(!in_array($value, $valuesUsed)) {
echo "<li> $key = $value </li>";
$valuesUsed[] = $value;
}
}
}
echo '</ul>';
return $valuesUsed;
}
Then I call the above function from my HTML template by
<div id="foo">
<?php
getByKey($routeTypes, 'en', 0, array());
?>
</div>
$routeTypes
is the array, obtained from the webservice.
It works as expected, it results as the list here below, which I can wrap with a js library.
<ul>
<li>this is level1</li>
<li>this is level1</li>
<li>
<ul>
<li>this is level 2</li>
<li>this is level 2</li>
<li>
... level++
</li>
</ul>
</li>
</ul>
Now, I'm questioning myself if this can be improved ? It doesn't take long to have a list from a large multidimensional array. (a simple print_r
command resulted in 45000+ characters).
Especially checking the $valuesUsed
array, to prevent duplicates (yes the webservice has objects which contains child keys which is similar to level - 2 parent (or on other level ...... ))
Each time I am running through the lower levels, I am looping through the $valuesUsed
array. Is there not a better way to loop through the sublevels ? Maybe an array_walk()
or array_walk_recursive()
with a callback function ?
-
\$\begingroup\$ Is this complete code ? It's seems to be missing some part ? Does it work on it's own ? Are you here for a review or something else ? \$\endgroup\$Marc-Andre– Marc-Andre2014年03月20日 14:03:05 +00:00Commented Mar 20, 2014 at 14:03
-
\$\begingroup\$ yes, i'm here for a review. Just asking if the recursive function can be improved. The above function will be called in the HTML template. (it displays the list of which i want on the webpage). Edited my post. \$\endgroup\$KarelG– KarelG2014年03月20日 14:09:31 +00:00Commented Mar 20, 2014 at 14:09
-
\$\begingroup\$ I was asking to come up with a title. The title of your question should describe what your code do! \$\endgroup\$Marc-Andre– Marc-Andre2014年03月20日 14:16:47 +00:00Commented Mar 20, 2014 at 14:16
1 Answer 1
You can choose a (key => value) pair recursively with this function:
function array_value_recursive($key, array $arr){
$val = array();
array_walk_recursive($arr, function($v, $k) use($key, &$val){
if($k == $key) array_push($val, $v);
});
return count($val) > 1 ? $val : array_pop($val);
}
This function makes use of array_walk_recursive() to push into a placeholder array whatever value is pointed to by whichever key matches our needle key.
Proof code:
$array = array(
'id' => 0,
'name' => array(
'it' => 'Tutti',
'ca' => 'Tots',
'es' => 'Todos',
'de' => 'Alle' ,
'fr' => 'Tous',
'nl' => 'Alle',
'en' => 'All'
),
'languages' => array(
"d" => 33
),
'subTypes' => array(
0 => array(
'id' => 1,
'name' => array(
'it' => 'Tutti',
'ca' => 'Tots',
'es' => 'Todos',
'de' => 'Alle' ,
'fr' => 'Tous',
'nl' => 'Alle',
'en' => 'All'
)
),
1 => array(
'id' => 1,
'name' => array(
'it' => 'Tutti',
'ca' => 'Tots',
'es' => 'Todos',
'de' => 'Alle' ,
'fr' => 'Tous',
'nl' => 'Alle',
'en' => 'All'
)
),
2 => array(
'id' => 1,
'name' => array(
'it' => 'Tutti',
'ca' => 'Tots',
'es' => 'Todos',
'de' => 'Alle' ,
'fr' => 'Tous',
'nl' => 'Alle',
'en' => 'All'
)
)
)
);
print_r(array_value_recursive("de", $array));
The above test code, which seeks all "de" keys, will output:
Array (
[0] => Alle
[1] => Alle
[2] => Alle
[3] => Alle
)
-
\$\begingroup\$ thanks for your suggestion, but yours code didn't kept the child level of the main array. The goal is to get a nested list (menu - submenu) as mentioned in my post. \$\endgroup\$KarelG– KarelG2014年03月24日 08:03:30 +00:00Commented Mar 24, 2014 at 8:03