I am returning a list of pages and their parent pages from a MySQL database and putting all results into an array as follows where every result is an array which includes the parent, name and id of the forum (the key of array pages is also the same as page id).
For the sake of the model and the applicaiton, there are some other parameters.
"root pages" have a parent of 0
there are no orphaned pages
so, the MySQL query will return this dataset.
pages=>
[1] => array(id=>1,
parent=>0,
name=>Hello World)
[2] => array(id=>1,
parent=>1,
name=>Child of Hello World)
[3] => array(id=>1,
parent=>0,
name=>Brother of Hello World)
[4] => array(id=>4,
parent=>2,
name=Grand-child of Hello World)
[6] => array(id=>6,
parent=>4,
name=Great-grand-child of Hello World)
i would then like to transform the array into something that looks like this
pages=>
[1] => id=>1,
name=>Hello World
children=>
[2] => id=>1
name=>Child of Hello World
children=>
[4] =>
id=>4
name=> Grand-child of Hello World)
children=>
[6] =>
id=>6
name=> Great-grand-child of Hello World
children= null
[3] => array(id=>1,
name=>Brother of Hello World
children=>null
So basically, i want to turn a linear array into a nested multidimensional array so that i can print my sitemap.
it needs to be a recursive solution. there are over 700 pages and up to 5 or 6 levels.
i only want to do 1 mysql query. not 700 so please dont give me a mysql based solution.
Here is a quick recursive function that builds a tree. Note that it's not great (one reason is because it doesn't get rid of items that have been already added to the tree, so each time you recurse it goes thru the entire list) - but it should work enough to get you started.
function buildTree($itemList, $parentId) {
// return an array of items with parent = $parentId
$result = array();
foreach ($itemList as $item) {
if ($item['parent'] == $parentId) {
$newItem = $item;
$newItem['children'] = buildTree($itemList, $newItem['id']);
$result[] = $newItem;
}
}
if (count($result) > 0) return $result;
return null;
}
$myTree = buildTree($myArray, 0);
<?php
$pages = array();
$pages[1] = array('id' => 1, 'parent' => 0, 'name' => 'Hello World');
$pages[2] = array('id' => 1, 'parent' => 1, 'name' => 'Child of Hello World');
$pages[3] = array('id' => 1, 'parent' => 0, 'name' => 'Brother of Hello World');
$pages[4] = array('id' => 4, 'parent' => 2, 'name' => 'Grand-child of Hello World');
$pages[6] = array('id' => 6, 'parent' => 4, 'name' => 'Great-grand-child of Hello World');
$children = array();
foreach($pages as $key => $page){
$parent = (int)$page['parent'];
if(!isset($children[$parent]))
$children[$parent] = array();
$children[$parent][$key] = array('id' => $page['id'], 'name' => $page['name']);
}
$new_pages = recursive_append_children($children[0], $children);
function recursive_append_children($arr, $children){
foreach($arr as $key => $page)
if(isset($children[$key]))
$arr[$key]['children'] = recursive_append_children($children[$key], $children);
return $arr;
}
print_r($new_pages);
?>
Outputs:
Array
(
[1] => Array
(
[id] => 1
[name] => Hello World
[children] => Array
(
[2] => Array
(
[id] => 1
[name] => Child of Hello World
[children] => Array
(
[4] => Array
(
[id] => 4
[name] => Grand-child of Hello World
[children] => Array
(
[6] => Array
(
[id] => 6
[name] => Great-grand-child of Hello World
)
)
)
)
)
)
)
[3] => Array
(
[id] => 1
[name] => Brother of Hello World
)
)
Related
How to create array parent and childrent with single array.
I did get all heading in the post of wordpress and i have a array like this.
array => ( array[0]([0] => 'title0', [1] => 'h2'),
array[1]([0] => 'title1', [1] => 'h2'),
array[2]([0] => 'title2', [1] => 'h3'),
array[3]([0] => 'title3', [1] => 'h3'),
array[4]([0] => 'title4', [1] => 'h3'),
array[5]([0] => 'title5', [1] => 'h2'),
array[6]([0] => 'title6', [1] => 'h3'), )
I want to build toggle list heading but i don't no how to do it with array i got it. i think with array parent and childrent can do it.
Please help me, How to build array parent and chilrent with array as notes above.
this is the code i did get all heading in the content wordpress.
function getallheading(){
$arr = array();
$pattern = '/(\<h[1-6](.*?))\>(.*?)(<\/h[1-6]>)/i';
preg_match_all($pattern, $content, $head);
foreach ($head[0] as $key_head => $val_head) {
$tag = substr($val_head, 1, 2);
if (in_array($tag, $head_check_box)) {
$arr_1['title'] = $val_head;
$arr_2['tag'] = $tag;
array_push($arr, [$arr_1['title'], $arr_2['tag']]);
}
return $arr.
}
I need to display a certain object from an array before showing the rest of the array.
The array looks like this:
Array
(
[0] => stdClass Object
(
[template_id] => 91
[template_name] => Alphabet
[template_thumbnail] => blank-template-thumbnail.jpg
[template_create_date] => 1456821665
[template_customer_id] => 0
[template_is_responsive] => no
[template_type] => builder
[template_category] => simple
[sort] => 2
)
[1] => stdClass Object
(
[template_id] => 92
[template_name] => Blank Template
[template_thumbnail] => blank-template-thumbnail.jpg
[template_create_date] => 1456821670
[template_customer_id] => 0
[template_is_responsive] => no
[template_type] => builder
[template_category] => simple
[sort] => 2
)
[2] => stdClass Object
(
[template_id] => 31
[template_name] => Holiday Specials
[template_thumbnail] => accommodation-1-20110926.jpg
[template_create_date] => 1456821660
[template_customer_id] => 0
[template_is_responsive] => no
[template_type] => builder
[template_category] => Accommodation
[sort] => 3
)
)
I need to show Blank Template first and then show the rest alphabetically (the order it is in now.
Is there a more elegant solution than looping through the array twice? The size of the array can be anything from 1 (the blank template) to countless objects.
$str="";
for($i=0;$i<=count($arr);$i++){
if($arr[$i]['template_name'] == "Blank Template"){
echo $arr[$i]['template_name'];
}else{
$str .= $arr[$i]['template_name']. "<br>";
}
}
echo $str;
Try this:
$firstItem = null;
$outArray = [];
foreach($yourArray as $item){
if($item->template_name == 'Blank Template'){
$firstItem = $item;
}else{
$outArray[$item->template_name] = $item;
}
}
ksort($outArray,SORT_STRING);
array_unshift($outArray,$firstItem);
Just one loop. Pay attention that this way of doing things, just work if you have uniqueness on the template_name!
Hope it helps.
This will work for you, try
<?php
$dataArray = array(0=>array('template_id'=>91,'template_name'=>'Alphabet'),
1=>array('template_id'=>92,'template_name'=>'Blank Template'),
2=>array('template_id'=>31,'template_name'=>'Holiday Specials')
);
$newArray = array();
foreach($dataArray as $key => $val)
{
if(in_array('Blank Template',$val))///find the key for black template
{
unset($dataArray[$key]); ///unset black temp from original array
$newArray[] = $val;///push black temp into new array at 0 index
foreach($dataArray as $k => $v)
{
$newArray[] = $v; ///push the renaming values into new array
}
}
}
echo "<pre>"; print_r($newArray);
?>
This will give you :
Array
(
[0] => Array
(
[template_id] => 92
[template_name] => Blank Template
)
[1] => Array
(
[template_id] => 91
[template_name] => Alphabet
)
[2] => Array
(
[template_id] => 31
[template_name] => Holiday Specials
)
)
LIVE EXAMPLE : CLICK HERE
The problem is to change a tree structure to a simple array structure, in which each child has the parents who belongs to, the example is a directories and files structure, but I'm looking for a generic solution.
If the writing is bad, feel free to improve it.
Any help is welcome.
Example.
$array_1=array(
'f1' =>
array(
'f2' =>array('file1.php','file2.php'),
'f3' =>array('file3.php','file4.php'),
'f4' =>
array(
'fol5'=>
array('fileAA.php','fileBB.php')
,
'fileDD.php'
),
),
'f2' =>
array(
'f2' =>array('file1.php','file2.php'),
'f3' =>array('file3.php'),
)
);
The result should be like this:
/*
0 => '/f1/f2/file1.php',
1 => '/f1/f2/file2.php',
2 => '/f1/f3/file3.php',
3 => '/f1/f3/file4.php',
4 => '/f1/f4/fol5/fileAA.php',
5 => '/f1/f4/fol5/fileBB.php',
6 => '/f1/f4/fileDD.php',
7 => '/f2/f2/file1.php',
8 => '/f2/f2/file2.php',
9 => '/f2/f3/file3.php',
*/
here is simple recursive function:
function tree2array($input, &$output, $prefix = '')
{
foreach ($input as $i => $v)
if (is_array($v))
tree2array($v, $output, $prefix.'/'.$i);
else
$output[] = $prefix.'/'.$v;
}
usage:
tree2array($array_1, $array2);
output:
print_r($array2);
Array (
[0] => /f1/f2/file1.php
[1] => /f1/f2/file2.php
[2] => /f1/f3/file3.php
[3] => /f1/f3/file4.php
[4] => /f1/f4/fol5/fileAA.php
[5] => /f1/f4/fol5/fileBB.php
[6] => /f1/f4/fileDD.php
[7] => /f2/f2/file1.php
[8] => /f2/f2/file2.php
[9] => /f2/f3/file3.php )
I made an alternative solution using SPL
$arrayiter = new RecursiveArrayIterator($array_1);
$iteriter = new RecursiveIteratorIterator($arrayiter,RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iteriter as $key => $value) {
$this_depth = $iteriter->getDepth();
if(!is_array($value)){
$array_2[] = '/'.$value;
$level[]=$this_depth;
}
foreach($array_2 as $key2 => $value2){
if($this_depth < $level[$key2]){
$level[$key2] = $this_depth;
$array_2[$key2] = '/'.$key.$value2;
}
}
}
echo'<pre>';
print_r($array_2);
echo'</pre>';
I've got an multi-array (currently with objects) that I want to reorder based on a specific key/value.
Array
(
[0] => stdClass Object
(
[task_id] => 1
[task_title] => Title
[users_username] => John
)
[1] => stdClass Object
(
[task_id] => 2
[task_title] => Title
[users_username] => John
)
[2] => stdClass Object
(
[task_id] => 3
[task_title] => Title
[users_username] => Mike
)
)
I'd like to reorder it to get multi-arrays by user_name, so I can cycle through the task by username.
Array
(
[John] => Array
(
[0] => Array
(
[task_id] => 1
[title] => Title
)
[1] => Array
(
[task_id] => 2
[title] => Title
)
)
[Mike] => Array
(
[0] => Array
(
[task_id] => 3
[title] => Title
)
)
)
Is it possible to recreate my array to an array like that above?
Updated version of the code
<?php
$it0 = (object) array('task_id' => 1,'task_title' => 'Title','users_username' => 'John');
$it1 = (object) array('task_id' => 2,'task_title' => 'Title','users_username' => 'John');
$it2 = (object) array('task_id' => 3,'task_title' => 'Title','users_username' => 'Mike');
$array = array($it0,$it1,$it2);
$return = array();
foreach($array as $id => $value){
$return[$value->users_username][] = array('task_id' => $value->task_id,'title' => $value->task_title);
}
var_dump($return);
Yes, it is possible.
You'll have to loop through your current array and create a new array to do it.
example:
$new_array = array();
foreach ($array as $row)
{
$new_row = array(
'task_id' => $row->task_id,
'title' => $row->task_title,
);
$name = $row->users_username;
if (isset($new_array[$name]))
{
$new_array[$name][] = $new_row;
}
else
{
$new_array[$name] = array($new_row);
}
}
Now $new_array contains the new array exactly like the one you're asking for.
Then you can sort it with
ksort($new_array);
There may be another way to do this, with some built-in function, but sometimes I'd rather just do it myself, and know how it is working, without having to look up the documentation.
The approach:
Iterate through all of the first array, looking at [users_username] and putting them into a new array.
Code:
$dst_array = array();
foreach ($src_array as $val)
{
$user = $val->users_username;
// TODO: This check may be unnecessary. Have to test to find out.
// If this username doesn't already have an array in the destination...
if (!array_key_exists($user, $dst_array))
$dst_array[$user] = array(); // Create a new array for that username
// Now add a new task_id and title entry in that username's array
$dst_array[$user][] = array(
'task_id' => $val->task_id
'title' => $val->title
);
}
Just something like this (maybe not 100% PHP code):
foreach ( $obj : $oldArray ) {
$newTask['task_id'] = $obj->task_id;
$newTask['title'] = $obj->title;
$newArray[$oldName][] = $newTask;
}
If you want to order it; you can just call a order function afterwards.
I am trying to figure out the best way to write a PHP function that will recursively build a multi-dimensional array with an unknown number of sublevels from a mysql table. Its purpose is to create a data structure which can be looped through to create a navigation menu on a website, with each menu item possibly having a submenu with child menu items.
The fields of note in the table are:
int ItemID
int ParentID
varchar ItemText
text ItemLink
tinyint HasChildren
So an example of a returned array from the function would be:
$menuItems =
array(
itemID# =>
array(
'ItemText' => 'Home',
'ItemLink' => 'index.php',
'Children' => array(
itemID# => array (
'ItemText' => 'Home Sub 1',
'ItemLink' => 'somepage.php',
'Children' => 0
),
itemID# => array (
'ItemText' => 'Home Sub 2',
'ItemLink' => 'somepage2.php',
'Children' => 0
),
)
),
itemID# =>
array(
'ItemText' => 'Contact',
'ItemLink' => 'contact.php',
'Children' => 0
)
)
);
Would greatly appreciate if someone could point me in the right direction to accomplish this. Thanks!
Not too hard. What you do is store the menu items in an array where you can look them up by ID. Then you iterate over the menu items and if they have a non-null ParentID you add them to their parent's list of children. Then you remove all the children from the master list so you have only top-level items left.
Code:
<?php
$menuItems = array
(
1 => array
(
'ItemText' => 'Home',
'ItemLink' => 'index.php',
'ParentID' => null,
),
2 => array
(
'ItemText' => 'Home Sub 1',
'ItemLink' => 'somepage.php',
'ParentID' => 1,
),
3 => array
(
'ItemText' => 'Home Sub 2',
'ItemLink' => 'somepage2.php',
'ParentID' => 1,
),
4 => array
(
'ItemText' => 'Contact',
'ItemLink' => 'contact.php',
'ParentID' => null,
),
);
// Each node starts with 0 children
foreach ($menuItems as &$menuItem)
$menuItem['Children'] = array();
// If menu item has ParentID, add it to parent's Children array
foreach ($menuItems as $ID => &$menuItem)
{
if ($menuItem['ParentID'] != null)
$menuItems[$menuItem['ParentID']]['Children'][$ID] = &$menuItem;
}
// Remove children from $menuItems so only top level items remain
foreach (array_keys($menuItems) as $ID)
{
if ($menuItems[$ID]['ParentID'] != null)
unset($menuItems[$ID]);
}
print_r($menuItems);
?>
Output:
Array
(
[1] => Array
(
[ItemText] => Home
[ItemLink] => index.php
[ParentID] =>
[Children] => Array
(
[2] => Array
(
[ItemText] => Home Sub 1
[ItemLink] => somepage.php
[ParentID] => 1
[Children] => Array
(
)
)
[3] => Array
(
[ItemText] => Home Sub 2
[ItemLink] => somepage2.php
[ParentID] => 1
[Children] => Array
(
)
)
)
)
[4] => Array
(
[ItemText] => Contact
[ItemLink] => contact.php
[ParentID] =>
[Children] => Array
(
)
)
)
Have a function that calls itself every time it gets an array element.
As in:
Your function is called to display a node. Then it checks if the node its calling from has a sub menu, and if does, it calls itself again. And the process repeats until it dies out, and all the previous function calls return.
void printData($mysql_table_node){
if($mysql_table_node.has_node()){
for($i = 0; $i < $mysqql_table_node.num_nodes()){
printData($mysql_table_node->own_node);
}
}
return;
}
Multi-dimensional tree and an unordered HTML list generator
Recursively build a tree from a multi-dimensional array.
Generate a multi-dimensional HTML list code, from the tree (1).
You can't never know how many dimensions is in the given list of items.
Each element can have a son->Grandson->Great grandson an so on.
So, you must use a recursive function to generate a multi-dimensional list.
Here is the code:
<?php
$categories = array(
'1'=> array('name'=>'one','parent'=>null),
'2'=> array('name'=>'two','parent'=>null),
'20'=> array('name'=>'twenty','parent'=>'2'),
'21'=> array('name'=>'twenty one','parent'=>'2'),
'210'=> array('name'=>'two hundred and ten', 'parent'=>'21'),
'211'=> array('name'=>'two hundred and eleven', 'parent'=>'21'),
'212'=> array('name'=>'two hundred and twelve', 'parent'=>'21')
);
$tree=Menu::CreateTree($categories);
print_r($tree);
Menu::GenerateMenuHtmlCode($tree);
class Menu
{
public static function GenerateMenuHtmlCode($tree)
{
echo '<ul>';
foreach ($tree as $key=>$value)
{
echo "<li>".$value['name'];
if(!empty($value['sons']))
self::GenerateMenuHtmlCode($value['sons']);
echo "</li>";
}
echo '</ul>';
}
public static function CreateTree($categories)
{
$tree=array();
self::AddElement(&$categories,&$tree,null);
return $tree;
}
private function AddElement($categories,&$tree,$parent)
{
foreach ($categories as $key=>$value)
{
if($value['parent']==$parent)
{
$tree[$key]=$categories[$key];
$tree[$key]['sons']=array();
self::AddElement($categories,&$tree[$key]['sons'],$key);
}
if(empty($tree['sons'])) unset ($tree['sons']);
}
unset($categories[$parent]);
return ;
}
}
?>
The result:
Array
(
[1] => Array
(
[name] => one
[parent] =>
[sons] => Array()
)
[2] => Array
(
[name] => two
[parent] =>
[sons] => Array
(
[20] => Array
(
[name] => twenty
[parent] => 2
[sons] => Array()
)
[21] => Array
(
[name] => twenty one
[parent] => 2
[sons] => Array
(
[210] => Array
(
[name] => two hundred and ten
[parent] => 21
[sons] => Array()
)
[211] => Array
(
[name] => two hundred and eleven
[parent] => 21
[sons] => Array()
)
[212] => Array
(
[name] => two hundred and twelve
[parent] => 21
[sons] => Array()
)
)
)
)
)
)
and:
<ul>
<li>one</li>
<li>two
<ul>
<li>twenty</li>
<li>twenty one
<ul>
<li>two hundred and ten</li>
<li>two hundred and eleven</li>
<li>two hundred and twelve</li>
</ul>
</li>
</ul>
</li>
</ul>
I know this is a late reply but I found this script above and it was fantastic. I ran into an issue though with it unsetting my children because of the way the ItemID was working, when I ran it with a similarly designed table to the OP. To get around this, and given the amount of RAM in most web servers should be able to handle this, I've taken John Kugelman's great example and modified it slightly. Instead of having to apply children to all of the items and then unsetting them after, I create a new array and build it all in one
Code:
$new_array = array();
foreach ($menuItems as $key => &$menuItem) {
if (($menuItem['ParentID'] != NULL) && ($menuItem['ParentID'] != '')) {
$new_array[$menuItem['ParentID']]['Children'][$menuItem['ItemID']] = &$menuItem;
} else {
$new_array[$menuItem['ItemID']] = &$menuItem;
}
}
print_r($new_array);
Hope this helps someone else because the above certainly helped me