Recursive function to generate multidimensional array from database result
Some very simple, generic tree building:
function buildTree(array $elements, $parentId = 0) {
$branch = array();
foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$children = buildTree($elements, $element['id']);
if ($children) {
$element['children'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
$tree = buildTree($rows);
The algorithm is pretty simple:
- Take the array of all elements and the id of the current parent (initially
0
/nothing/null
/whatever). - Loop through all elements.
- If the
parent_id
of an element matches the current parent id you got in 1., the element is a child of the parent. Put it in your list of current children (here:$branch
). - Call the function recursively with the id of the element you have just identified in 3., i.e. find all children of that element, and add them as
children
element. - Return your list of found children.
In other words, one execution of this function returns a list of elements which are children of the given parent id. Call it with buildTree($myArray, 1)
, it will return a list of elements which have the parent id 1. Initially this function is called with the parent id being 0, so elements without parent id are returned, which are root nodes. The function calls itself recursively to find children of children.
Build a multidimensional array using recursive function
You do not need recursion here. In fact, it will be very inefficent since you end up with a SELECT N+1 issue. Just order the result set by parent:
$query = "SELECT CID, Item, Parent FROM betyg_category WHERE Status = '1' ORDER BY Parent";
$result = mysql_query($query);
$tree = array();
while($row = mysql_fetch_assoc($result)) {
if($row['Parent'] == 0) {
$row['Children'] = array();
$tree[$row['CID']] = $row;
} else {
$tree[$row['Parent']]['Children'][] = $row;
}
}
This will produce the following:
Array
(
[1] => Array
(
[CID] => 1
[Item] => Litteratur
[Parent] => 0
[Children] => Array
(
[0] => Array
(
[CID] => 2
[Item] => Integration av källorna
[Parent] => 1
)
[1] => Array
(
[CID] => 3
[Item] => Belysning
[Parent] => 1
)
[2] => Array
(
[CID] => 4
[Item] => Referenser
[Parent] => 1
)
)
)
[5] => Array
(
[CID] => 5
[Item] => Validitet
[Parent] => 0
[Children] => Array
(
[0] => Array
(
[CID] => 6
[Item] => Huvudsyfte
[Parent] => 5
)
)
)
)
If you only want the name of each children, change, use $tree[$row['Parent']]['Children'][] = $row['Item']
; instead.
Recursive function to generate multidimensional array and count nested children
One of the issues with working with recursive arrays and recordsets is that unless you are just displaying the results you end up rewriting a lot of code to be able to manipulate the data.
For example if you remove a child, you have to iterate over the entire array in order to update the rest of the tree, or writing another function to flatten the array tree to iterate over and retrieve the node properties.
What happens if you need to find the depth or the root node of a particular node instead of just the number of children?
Try an object to store your tree which can keep track of inheritance and execute functionality that arrays can't. This will make working with the recordsets easier and less time consuming when trying to figure out recursion and if you need to add functionality to it.
Here is an example of what I have used in the past before writing an ORM.
https://3v4l.org/PgqlG
I designed it to be able to iterate over the entire tree (flat array), a single node, or a node's children. I also needed the child count, how far down the node was in the tree (depth), and to be able to find the root node. Hope it helps.
/**
* Provides a flat list of all the nodes
* Eases with modifying the tree inheritance by id
*/
class NodeList
{
public $length = 0;
/**
* @param mixed $index
* @return Node|null
*/
public function item($index)
{
$tmp = (array) $this;
$this->length = count($tmp) - 1;
if (false === isset($this->$index)) {
return null;
}
return $this->$index;
}
}
/**
* Establish and maintain the tree view of each node/child
*/
class Tree extends NodeList
{
/**
* Requires id, parent from record set
* @param null|array|object $recordSet
*/
public function __construct($recordSet = null)
{
if (null !== $recordSet) {
$this->setChildren($recordSet);
}
}
/**
* @param array|object $recordSet
*/
private function setChildren($recordSet)
{
foreach ($recordSet as $record) {
if (true === is_array($record)) {
$record = (object) $record;
}
if (true === isset($record->id)) {
$this->length++;
$this->appendNode($record->id, $record);
}
}
foreach ($this as $node) {
if (false === $node instanceof Node) {
continue;
}
if (false === empty($node->parent) && true === isset($this->{$node->parent})) {
$children = &$this->{$node->parent}->children;
$children->length++;
$children->{$node->id} = &$this->{$node->id};
$this->item($node->id);
}
}
}
/**
* @param string $id
* @param null|array|object $data
* @return mixed
*/
public function appendNode($id, $data = null)
{
$this->$id = new Node($data);
return $this->item($id);
}
/**
* @param string $id
* @return \Node
*/
public function getNode($id)
{
$item = $this->item($id);
if (true === empty($item)) {
$this->appendNode($id, null);
}
return $item;
}
/**
* @param string $id
* @return \Node|null
*/
public function getParent($id)
{
if (null === $this->getNode($id)->parent) {
return null;
}
return $this->getNode($this->getNode($id)->parent);
}
/**
* @param string $id
* @return int
*/
public function getDepth($id)
{
$i = 0;
$item = $this->item($id);
if (null !== $item && null !== $item->parent) {
$i = $this->getDepth($item->parent) + 1;
}
$item->depth = $i;
return $item->depth;
}
/**
* @param string $id
*/
public function removeNode($id)
{
$this->removeChildren($id);
if (null !== $this->item(id)) {
$parent = false;
if ($this->item($id)->parent) {
$parent = $this->getParent($id);
}
$this->$id = null;
if ($parent && $parent->children) {
unset($parent->children->$id);
$parent->children->length--;
}
}
}
}
/**
* Single Node
* This is an overloaded class
*/
class Node
{
public $id;
public $name;
public $parent;
public $depth;
public $children;
/**
* @param array|object $data
*/
public function __construct($data)
{
$this->children = new NodeList();
if (null === $data) {
return;
}
foreach ($data as $key => $value) {
/* I escaped these values since they are redundant to this script */
switch ($key) {
case 'children':
case 'depth':
case 'childrenCount':
continue 2;
}
$this->$key = $value;
}
}
/**
* @return int
*/
public function countChildren()
{
return $this->children->length;
}
/**
* @return \NodeList
*/
public function getChildren()
{
return $this->children;
}
public function removeChildren()
{
if (null !== $this->getChildren()) {
foreach ($this->children as $child) {
if (true === isset($child->children)) {
$child->removeChildren();
}
$child = null;
}
}
$this->children = null;
return $this;
}
}
recursively database filling with multidimensional array
It's done,I found another way to retrieve the data that I wanted.
function RecursiveAddOfProducts($listeSon,$listParents_libelle) {
$result = array();$Product=array();
if($listeSon) {
foreach($listSon as $key => $currentNode {
if(!empty($currentNode)) { // If the product has a son
$newParent_libelle = $listParents_libelle;
$newParent_libelle[] = utf8_decode($currentNode['libelle']);
$newParent_id=$listParents_id;
$newParent_id[] = $currentNode['id'];
$produit=array_merge($newParent_id,$newParent_libelle);
$menu_niveau=count($Product)-1;
ProductInsert($Product,$menu_niveau);
RecursiveAddOfProducts($currentNode['fils'], $newParent_libelle);
}
}
}
}
$listeParents=array();
RecursiveAddOfProducts($tab_categories,$listParents);
My insert function works like it :
function ProductInsert($tab,$menu_niveau){
$menu_list = "";
$column_value = "";
for($i=1;$i<= $menu_level ;$i++){
if($menu_list != '')
$menu_list .= ', ';
$menu_list .= "menu".$i;
if($column_value != '')
$column_value .= ', ';
$column_value.= "'".addslashes($tab[$i])."'";
//var_dump($column_value);
}
$req="INSERT IGNORE INTO menu_itm (id, ".$menu_list.",menu_niveau)
VALUES(".$tab[0].",".$column_value.",'".$menu_level."')";
echo $req."</br>";
sql($req);
}
I would like all to thank you for your help, all the persons which contributed was of a big help. I learnt a lot. Thanks to Ryan vincent also for your help, you gave many of your time, I am grateful to you for it.;)
How to create multidimensional array unlimited depth array with parent and child came from single table
Credits to Recursive function to generate multidimensional array from database result
I solved my problem with this code
public function buildTree(array $elements, $parentId = 0) {
$branch = array();
foreach ($elements as $element) {
if ($element['parent_id'] == $parentId) {
$children = $this->buildTree($elements, $element['id']);
$isArray = filter_var($element['isArray'], FILTER_VALIDATE_BOOLEAN);
if ($isArray) {
$element['isArray'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
Loop into multidimensional array from top to bottom
This should do the job.
$arr = array(
array(
'id' => 1,
'parent_id' => 0,
'title' => 'Parent Page',
'children' => array(
array(
'id' => 2,
'parent_id' => 1,
'title' => 'Sub Page',
),
array(
'id' => 5,
'parent_id' => 1,
'title' => 'Sub Page 2',
'children' => array(
array(
'id' => 7,
'parent_id' => 5,
'title' => 'Sub Page',
),
array(
'id' => 8,
'parent_id' => 5,
'title' => 'Sub Page 2',
)
)
)
)
),
array(
'id' => 4,
'parent_id' => 0,
'title' => 'Another Parent Page',
)
);
function printAll($arr, $parent = [])
{
if (is_array($arr)) {
foreach ($arr as $k => $v) {
if (isset($v['id'])) {
$parent[] = $v['id'];
echo implode('.', $parent) . PHP_EOL;
}
if (isset($v['children'])) {
printAll($v['children'], $parent);
}
array_pop($parent);
}
}
}
printAll($arr);
Output
1
1.2
1.5
1.5.7
1.5.8
4
Working demo.
Related Topics
PHP Generate File For Download Then Redirect
Preg_Match(): Compilation Failed: Invalid Range in Character Class At Offset
PHP Foreach Change Original Array Values
How to Evaluate Formula Passed as String in PHP
How to View Query Error in Pdo PHP
When Should I Use MySQLi Instead of MySQL
Strange Character Encoding of Stored Data , Old Script Is Showing Them Fine New One Doesn'T
How to Properly Add Cross-site Request Forgery (Csrf) Token Using PHP
How to Repair a Serialized String Which Has Been Corrupted by an Incorrect Byte Count Length
Return Single Column from a Multi-Dimensional Array
How to Load Classes Based on Pretty Urls in MVC-Like Page
Woocommerce: Auto Complete Paid Orders
How to Let PHP to Create Subdomain Automatically For Each User