Ok, so say I have an array as follows:
$buttons = array(
'mlist' => array(
'title' => 'Members',
'href' => $scripturl . '?action=mlist',
'show' => $context['allow_memberlist'],
'sub_buttons' => array(
'mlist_view' => array(
'title' => 'View the Member List',
'href' => $scripturl . '?action=mlist',
'show' => true,
),
'mlist_search' => array(
'title' => 'Search for Members',
'href' => $scripturl . '?action=mlist;sa=search',
'show' => true,
'is_last' => true,
),
),
),
'home' => array(
'title' => 'Home',
'href' => $scripturl,
'show' => true,
'sub_buttons' => array(
),
'is_last' => $context['right_to_left'],
),
'help' => array(
'title' => 'Help',
'href' => $scripturl . '?action=help',
'show' => true,
'sub_buttons' => array(
),
),
);
I need to sort through this array and return all indexes of it in another array as an index, and the values of these arrays will be the title. So it should return an array as follows:
array(
'mlist' => 'Members',
'mlist_view' => 'View the Member List',
'mlist_search' => 'Search for Members',
'home' => 'Home',
'help' => 'Help',
);
How can this be achieved easily? Basically, need the key of each array if a title is specified and need to populate both within another array.
-
What do you think how this can be done?hakre– hakre2011年09月28日 19:28:22 +00:00Commented Sep 28, 2011 at 19:28
4 Answers 4
The following snippet loops over all of the arrays (recursively) to extract the key/title pairs.
$index = array();
$iterator = new RecursiveIteratorIterator(new ParentIterator(new RecursiveArrayIterator($buttons)), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $key => $value) {
if (array_key_exists('title', $value)) {
$index[$key] = $value['title'];
}
}
var_dump($index);
9 Comments
RecursiveIteratorIterator
class built into all servers that have php enabled? Also, what version of PHP is required for this class to work in?How can this be achieved easily?
- initialize an empty, new array
- foreach the
$buttons
array with key and value- extract title from value
- set the key in the new array with the title
- done.
Edit: In case a recursive array iterator catches too much (identifying elements as children while they are not - just being some other array), and you don't want to write an extension of the recursive iterator class, stepping through all children can be solved with some "hand written" iterator like this:
$index = array();
$childKey = 'sub_buttons';
$iterator = $buttons;
while(list($key, $item) = each($iterator))
{
array_shift($iterator);
$index[$key] = $item['title'];
$children = isset($item[$childKey]) ? $item[$childKey] : false;
if ($children) $iterator = $children + $iterator;
}
This iterator is aware of the child key, so it will only iterate over childs if there are some concrete. You can control the order (children first, children last) by changing the order:
if ($children) $iterator = $children + $iterator;
- or -
if ($children) $iterator += $children;
3 Comments
ParentIterator
returns all Iterator
on arrays and objects that have at least one key/property that contains another array or object. In your case you only have children if it's an array and the key is named sub_buttons
. That's what I meant with "catches too much" you might not want to traverse into any sub array / object just by var-type, but more specific. But this depends. And you would need to extend RecursiveArrayIterator
/ParentIterator
to only return the children you need. The code to do that, nobody wanted to write for the demo. I assume it's much larger.I'm sure my answer is not most efficient, but using many foreach loops and if checks, it can be done. However, with my solution if you nested another array inside of say 'mlist_view' that you needed to get a title from, it would not work. My solution works for a max of 2 arrays inside of arrays within buttons. A better (and more general purpose solution) would probably involve recursion.
$result = array();
foreach($buttons as $field => $value) {
foreach($value as $nF => $nV) {
if($nF === 'title') {
$result[$field] = $nV;
}
if(is_array($nV)) {
foreach($nV as $name => $comp) {
if(is_array($comp)) {
foreach($comp as $nnF => $nnV) {
if($nnF === 'title') {
$result[$name] = $nnV;
}
}
}
}
}
}
}
foreach($result as $f => $v) {
echo $f.": ".$v."<br/>";
}
Comments
This works for your value of $buttons, fairly simple:
function get_all_keys($arr) {
if (!is_array($arr)) return array();
$return = array();
foreach (array_keys($arr) as $key) {
if (is_array($arr[$key])
&& array_key_exists('title', $arr[$key]))
$return[$key] = $arr[$key]['title'];
$return = array_merge($return, get_all_keys($arr[$key]));
}
return $return;
}
echo "<pre>";
print_r(get_all_keys($buttons));
echo "</pre>";
Which returns:
Array
(
[mlist] => Members
[mlist_view] => View the Member List
[mlist_search] => Search for Members
[home] => Home
[help] => Help
)