i am trying to create a multidimensional array hierarchy from a simple array which contains pairs of category ids and parent ids. The categories can be a parent and a subcategor
Is there any way you can change the way that the array is generated? As you have it now, will be more hassle then it's worth to try and generate what you want.
Alternatively, you could try and generate something like this:
$menu = array(
0 => array(0, 1, 2, 3),
1 => array(0, 1),
);
Allowing a simple loop like this:
<ul>
<?php foreach ($menu as $parent => $subs) : ?>
<li>
<?php echo $parent; ?>
<ul>
<?php foreach ($subs as $index => $val): ?>
<li>
<?php echo $val; ?>
</li>
<?php endforeach; ?>
</ul>
</li>
<?php endforeach; ?>
</ul>
The above is templating syntax, I'm sure we all know what this is so I'm now going to explain it.
Or the simple loop would look like this:
echo "<ul>";
foreach($menu as $parent => $subs){
echo "<li>";
echo $parent;
echo "<ul>";
foreach($subs as $index => $val) {
echo "<li>";
echo $val;
echo "</li>";
}
echo "</ul>";
echo "</li>";
}
echo "</ul>";
Well it appears to me you need a recursive function. Assuming everything has a parent or value beginning at the base level of 0, I resituated the array to have all parent ids listing their children rather than the other way around above. After that, I created a recursive function.
$initialArray = array(
1 => 0,
2 => 1,
3 => 2,
4 => 0,
5 => 4,
6 => 0
);
// resituate the array
$parent_ids = array();
foreach ($initialArray as $category_id => $parent_id) {
if (!isSet($parent_ids[$parent_id])) {
$parent_ids[$parent_id] = array();
}
$parent_ids[$parent_id][] = $category_id;
}
// end_array is the result
$end_array = array();
/**
* Takes the key of the parent, the current set that it's working off of, the list of parent ids for reference
* and the current place in the end result array, acting recursively
*/
function recursive($parent_key, $current_set, $parent_ids, $end_array) {
foreach ($current_set as $parent_value) {
if (!isSet($parent_ids[$parent_value])) {
$end_array[$parent_key][] = $parent_value;
} else {
// if the parent_value is found in parent_ids, pass those values to the same function and the current end_array position
$end_array[$parent_key] = recursive($parent_value, $parent_ids[$parent_value], $parent_ids, $end_array[$parent_key]);
}
}
return $end_array;
}
// start with the top most element
$end_array = recursive(key($parent_ids), current($parent_ids), $parent_ids, $end_array);
print '<pre>'.
print_r($parent_ids, true).
print_r($end_array,true).
'</pre>'
;
Outputs:
// resituated array
Array
(
[0] => Array
(
[0] => 1
[1] => 4
[2] => 6
)
[1] => Array
(
[0] => 2
)
[2] => Array
(
[0] => 3
)
[4] => Array
(
[0] => 5
)
)
// the end result
Array
(
[0] => Array
(
[1] => Array
(
[2] => Array
(
[0] => 3
)
)
[4] => Array
(
[0] => 5
)
[5] => 6
)
)
I know, late to the party but it looks interesting...
/*
* This is a 'multiway' tree where:
* a 'parent' can have any number of 'child' nodes
* therefore the 'parent node' must look like:
* [parentId] => array()
*
* where [parentId] is the index of an array;
*/
It will insert one node at a time starting from the root node. It can get very expensive for large trees.
Working example at: Viper-7.com
The routine that does the work:
/**
* Insert: Find the 'parent' node
* if child not found then insert a 'node'
*
* @param array node passed by reference as the new node will be inserted
* @param integer $parentId - root Id must be the lowest value
* @param integer $childId
* @return boolean true if parentId found and processed
*/
function insertNode(&$node, $parentId, $childId) {
if (isset($node[$parentId])) { // this node will be processed
if (!isset($node[$parentId][$childId])) {
$node[$parentId][$childId] = array(); // add child node
return true;
}
return true; // end of processing
}
// check all the children of this node...
foreach($node as &$child) { // need the reference
if (insertNode($child, $parentId, $childId)) {
return true;
}
}
return false; // parentId not in the tree
}
Notes:
The node to be processed is passed by reference.
The processing will end when the 'parent' id is found
The input node list as given is 'child' => 'parent' order which is unusual, it is ok, just remember that in the processing...
Process the input data:
$theTree = array(current($links) => array()); // root
// insert all the child nodes into the tree
foreach($links as $childId => $parentId) {
$inserted = insertNode($theTree, $parentId, $childId);
}
// output the tree
echo '<pre>', 'Children are in the same order as the input array.', '<br />';
print_r($theTree);
echo '</pre>';
The input list needs to be arraged so that the 'tree' will be loaded such that the parent of the child to be added must be in the tree already. i assume that the input list is in the required order already
Test data, sort and display:
# cat_id => parent_id
$links = array(
1 => 0,
2 => 1,
3 => 2,
4 => 0,
5 => 4, // multiple children
11 => 4,
99 => 4,
13 => 11,
6 => 0
);
Output, i added a sub-tree to the original input...
Children are in the same order as the input array.
Array
(
[0] => Array
(
[1] => Array
(
[2] => Array
(
[3] => Array
(
)
)
)
[4] => Array
(
[5] => Array
(
)
[11] => Array
(
[13] => Array
(
)
)
[99] => Array
(
)
)
[6] => Array
(
)
)
)
Get your list :
<?php
$initialArray = array(
1 => 0,
2 => 1,
3 => 2,
4 => 0,
5 => 4,
6 => 0
);
$menus = array();
function generateMenus($start) {
global $initialArray;
foreach($initialArray as $k => $v) {
if($start == $v) {
$menus[] = $k;
}
}
return $menus;
}
$final = array();
foreach($initialArray as $key => $value) {
$final[$value] = generateMenus($value);
}
echo '<ul>';
function generateList($start) {
global $final;
echo '<li>'.$start.'</li>';
if(!empty($final[$start])) {
echo '<ul>';
foreach($final[$start] as $v) {
generateList($v);
}
echo '</ul>';
}
}
generateList(0);
echo '</ul>';
?>
If you want to form a recursive array you can refer on this page
Recursive function to generate multidimensional array from database result
this may help you a lot. Thanks.
You can make an array like this
$initialArray = array();
$initialArray[parent_id][cat_id]='your_value'; //$initialArray[0][0] ... and then increasing