Recursive Function to Generate Multidimensional Array from Database Result

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:

  1. Take the array of all elements and the id of the current parent (initially 0/nothing/null/whatever).
  2. Loop through all elements.
  3. 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).
  4. 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.
  5. 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



Leave a reply



Submit