Hierarchy in the array РHP - php

I have a function that build a Tree Array. Example:
Array
(
[0] => Array
(
[id] => 12
[address] => 'Ukraine'
[parent_id] => 0
[children] => Array
(
[0] => Array
(
[id] => 11
[address] => Crimea
[parent_id] => 12
[children] => Array
(
[0] => Array
(
[id] => 16
[address] => Yalta
[parent_id] => 11
)
)
)
)
)
I have function to print Tree (I want to get output with levels indented):
function printTree($data) {
foreach ($data as $item) {
if ($item['parent_id'] != 0)
echo ' - ' . $item['address'] . "<br>";
else
echo $item['address'] . "<br>";
if (isset($item['children'])) {
printTree($item['children']);
}
}
}
But my result is only with one levels indets, because my if is not correct:
Ukraine
- Crimea
- Yalta
I need to get with all levels indents. What do I need to change in my if statement?
Ukraine
- Crimea
- Yalta

Rewrite your code this way:
function printTree($data, $level = 0) {
foreach ($data as $item) {
if ($item['parent_id'] != 0) {
/* here we corrects indent: */
echo str_repeat(' ', $level) . ' - ' . $item['address'] . "<br>";
} else {
echo $item['address'] . "<br>";
}
if (isset($item['children'])) {
printTree($item['children'], $level + 1);
}
}
}

You just add a depth variable to control how many blanks you want add before each child item:
<?php
$data = array(
0 => array(
'id' => 12,
'address' => 'Ukraine',
'parent_id' => 0,
'children' => array(
0 => array(
'id' => 11,
'address' => Crimea,
'parent_id' => 12,
'children' => array(
0 => array(
'id' => 16,
'address' => Yalta,
'parent_id' => 11,
)
)
)
)
)
);
printTree($data);
function printTree($data, $depth = 0) {
foreach ($data as $item) {
if ($item['parent_id'] != 0)
echo str_repeat(' ', $depth), "- {$item['address']}\n";
else
echo "{$item['address']}\n";
if (isset($item['children'])) {
printTree($item['children'], ++$depth);
}
}
}
Output:
Ukraine
- Crimea
- Yalta
Working demo.

Related

Using array after POST

I would like to edit database entries with a simple form.
The id and name of each entry is fixed.
Problems:
After submitting the form $farray does only include the edited data of $array[3] not of the other records.
$farray doesn't include name and id (not included in the form). I need the id of the record for the query.
What could I use as a workaround?
Current script
<?php
$query = mysql_query("SELECT * FROM database");
$array = array();
while($row = mysql_fetch_assoc($query)){
$array[] = $row;
}
if(isset($_POST['send']))
{
$farray = $_POST['farray'];
foreach ($farray as $key => $value) {
echo('UPDATE database SET ' . $key . ' = "' . $value . '"' . ' WHERE id = ' . $farray['id']); //testing
}
}
?>
<form action=" <?=$_SERVER['PHP_SELF']?> " method="POST">
<?php
foreach($array as $key1){
echo $key1["name"] . "<br />";
foreach($key1 as $key => $value){
if ($key != "id" AND $key != "name") {
print $key.
' <input type="text" name="farray['.$key.']" value="'.$value.'"><br /><br />';
}
}
}
?>
<input type="submit" name="send" value="send">
</form>
Example $array
Array
(
[0] => Array
(
[id] => 0
[name] => name0
[1] => 1
[2] => 2
[3] => 3
)
[1] => Array
(
[id] => 1
[name] => name1
[1] => 1
[2] => 2
[3] => 3
)
[2] => Array
(
[id] => 2
[name] => name2
[1] => 1
[2] => 2
[3] => 3
)
[3] => Array
(
[id] => 3
[name] => name3
[1] => 1
[2] => 2
[3] => 3
)
)
Example $farray (after editing and submitting form)
Array
(
[1] => 10
[2] => 20
[3] => 30
)
OK, even though your table fields are not 1, 2, and 3, you just needed to change up your posted array a little. So I made you a little example:
<form method="post">
<?php
// Simulate DB records
$array = [
[
'id' => 0,
'name' => 'name0',
'1' => 1,
'2' => 2,
'3' => 3
],
[
'id' => 1,
'name' => 'name1',
'1' => 1,
'2' => 2,
'3' => 3
],
[
'id' => 2,
'name' => 'name2',
'1' => 1,
'2' => 2,
'3' => 3
]
];
// Create the input fields:
foreach( $array as $key1 )
{
echo $key1["name"] . "<br />";
foreach($key1 as $key => $value)
{
if ($key != "id" AND $key != "name")
{
echo $key.
' <input type="text" name="farray[' . $key1['id'] . ']['.$key.']" value="'.$value.'"><br /><br />';
}
}
}
?>
<button type="submit">Submit</button>
</form>
<pre>
<?php
if( isset( $_POST['farray'] ) )
{
print_r( $_POST );
foreach( $_POST['farray'] as $id => $values )
{
foreach( $values as $k => $v )
{
echo('UPDATE database SET ' . $k . ' = "' . $v . '"' . ' WHERE id = ' . $id ) . '<br />';
}
}
}
?>
</pre>
I tested this, and I think it works as you would expect.

Recursive Multidimensional Array to HTML nested code

Im trying to create nested blocks of HTML code from a Multidimensional Array in PHP using a recursive function. However I can not seem to print the tags in a nested order.
Here is the original array:
$array_1 =
array
(
array
(
'id' => '1',
'tag' => 'div1',
'parent' => '0'
),
array
(
'id' => '2',
'tag' => 'div2',
'parent' => '1'
),
array
(
'id' => '3',
'tag' => 'div3',
'parent' => '2'
),
array
(
'id' => '4',
'tag' => 'div4',
'parent' => '2'
),
array
(
'id' => '5',
'tag' => 'div5',
'parent' => '0'
),
array
(
'id' => '6',
'tag' => 'div6',
'parent' => '5'
),
array
(
'id' => '7',
'tag' => 'div7',
'parent' => '0'
)
);
The first thing I do is to use a function to turn this array into a multidimensional array by building a tree structure using the parent element of each record as reference:
function buildTree(array $elements, $parentId = 0) {
$branch = array();
foreach ($elements as $element)
{
if ($element['parent'] == $parentId)
{
$children = buildTree($elements, $element['id']);
if ($children)
{
$element['children'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}
$tree_1 = buildTree($array_1);
Once this is done the multidimensional array should look like this:
Array
(
[0] => Array
(
[id] => 1
[name] => div1
[parent] => 0
[children] => Array
(
[0] => Array
(
[id] => 2
[name] => div2
[parent] => 1
[children] => Array
(
[0] => Array
(
[id] => 3
[name] => div3
[parent] => 2
)
[1] => Array
(
[id] => 4
[name] => div4
[parent] => 2
)
)
)
)
)
[1] => Array
(
[id] => 5
[name] => div5
[parent] => 0
[children] => Array
(
[0] => Array
(
[id] => 6
[name] => div6
[parent] => 5
)
)
)
[2] => Array
(
[id] => 7
[name] => div7
[parent] => 0
)
)
The next thing to do is to output the html elements in a nested order. In this example Im using symbolic tag names such as div1, div2, etc; but in reality they could be any html tags like divs, h1, ul,li, form, etc; with their opening and closing tags.
To accomplish this I use the following recursive function, however my problem is that it does not show the html elements in a nested order as they should be.
function recursive($array, $level = 0)
{
foreach($array as $key => $value)
{
if (!is_array($value) && $key == "tag") { echo str_repeat(" ", $level), "[".$value."]", ''; }
//If $value is an array.
if(is_array($value))
{
//We need to loop through it.
recursive($value, $level + 1);
}
else
{
//It is not an array, so print it out.
if ($key == "tag") { echo "[/".$value."]", '<br>'; }
}
}
}
$tree_2 = recursive($tree_1);
echo $tree_2;
This is how it currently outputs the html tags from the array:
[div1][/div1]
[div2][/div2]
[div3][/div3]
[div4][/div4]
[div5][/div5]
[div6][/div6]
[div7][/div7]
And this is how the html tags should be output in reality based on the multidimensional array's nested order (please note how some div tags contain other div tags before their closing element):
[div1]
[div2]
[div3][/div3]
[div4][/div4]
[/div2]
[/div1]
[div5]
[div6][/div6]
[/div5]
[div7][/div7]
How can I get the html tags printed in the right nested order like in the last example? What am I missing? Thanks so much!
The issue is that the key tag is before children in the $tree_1 array.
Whilst I would personally change your data structure around to make it "easier" to use in the recursive function, you can change your recursive function to make it work like this:
function recursive($array, $level = 0)
{
// Check if we are using an associative array or indexed array
if(isset($array['tag'])) {
echo str_repeat(" ", $level), "[" . $array['tag'] . "]", '';
if(isset($array['children'])) {
echo "<br />";
recursive($array['children'], $level + 1);
echo str_repeat(" ", $level), "[/" . $array['tag'] . "]" , '';
} else {
echo "[/" . $array['tag'] . "]";
}
echo "<br />";
} else {
foreach($array as $key => $value)
{
recursive($value, $level + 1);
}
}
}
Add additional line breaks and formatting where required
A rewrite of your function:
function recursive2($array, &$level, $indentClosingTag = true)
{
$level++;
for($i = 0; $i<count($array); $i++) {
$data = $array[$i];
$indent = str_repeat(' ', $level);
echo $indent . "[".$data['tag'].']';
if (isset($data['children'])) {
echo '<br>';
$level++;
recursive2($data['children'], $level, true);
$level--;
} else {
$indentClosingTag = false;
}
echo ($indentClosingTag ? $indent : ''). "[/".$data['tag'].']'.'<br>';
}
$level--;
}
$l = 0;
recursive2($tree_1, $l);

From php multidimensional array trying to create nested ul li menu (unlimited nested levels)

Here is what i have got http://codepad.org/iDoXXsLX
Have array like this
Array
(
[0] => Array
(
[NumberRenamed] => 17
[TopicName] => Products
[UpperLevelNumberRenamed] => 0
)
[17] => Array
(
[0] => Array
(
[1] => Array
(
[NumberRenamed] => 18
[TopicName] => Computers
[UpperLevelNumberRenamed] => 17
)
)
)
[18] => Array
(
[0] => Array
(
[2] => Array
(
[NumberRenamed] => 16
[TopicName] => Laptops
[UpperLevelNumberRenamed] => 18
)
)
)
[16] => Array
(
[0] => Array
(
[4] => Array
(
[NumberRenamed] => 8
[TopicName] => Dell
[UpperLevelNumberRenamed] => 16
)
)
)
)
Top level item is Products, first sub-level item is Computers, next sub-level is Laptops, then again next sub-level Dell
For each sub-level item UpperLevelNumberRenamed == to closest upper level NumberRenamed.
Want to get result like this
Products
Computers
Laptops
Dell
Acer
Desktops
Home
Tried this
foreach( $main_topics as $k_main_topics => $v_main_topics ){
if( isset($v_main_topics['UpperLevelNumberRenamed']) and $v_main_topics['UpperLevelNumberRenamed'] == 0 ){
//print only top level topics
echo $v_main_topics['TopicName']. '<br/>';
}
else{//if not top level topic
foreach( $v_main_topics[0] as $k_v_main_topics_0 => $v_v_main_topics_0 ){
echo $v_v_main_topics_0['TopicName']. '<br/>';
}//foreach( $v_main_topics[0] as $k_v_main_topics_0 => $v_v_main_topics_0 )
}//else{
}//foreach( $main_topics as $k_main_topics => $v_main_topics )
But get this
Products
Home
Computers
Laptops
Desktops
Dell
Acer
Something incorrect, but can not understand what. Please, advice what need to correct/change in the code
Trying another way
Initial array is one dimensional array. Trying to get ul li navigation from one dimensional.
Here is what i did http://codepad.org/OLtxyL4X
Here's a summary of what it does:
flatten the array recursively
build a multi-dimensional relation map
create 1D relationships that link UpperLevelNumberRenamed to NumberRenamed
print out the multi-dimensional as an ul-li list.
Here it is:
$flat = array();
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($main_topics)) as $i)
$flat[] = $i;
$final = array();
$defs = array();
for ($i = 0; $i < count($flat); $i += 3)
if ($flat[$i + 2] == 0) {
$final[$flat[$i + 1]] = array();
$defs[$flat[$i]] = &$final[$flat[$i + 1]];
} else {
$defs[$flat[$i + 2]][$flat[$i + 1]] = array();
$defs[$flat[$i]] = &$defs[$flat[$i + 2]][$flat[$i + 1]];
}
function array2ul($array) {
$out = "<ul>";
foreach($array as $key => $elem)
$out = is_array($elem) ?
$out . "<li><span>$key</span>" . array2ul($elem) . "</li>" :
$out = $out."<li><span>$key:[$elem]</span></li>";
$out = $out . "</ul>";
return $out;
}
echo array2ul($final);
Output:
<ul><li><span>Products</span><ul><li><span>Computers</span><ul><li><span>Laptops</span><ul><li><span>Dell</span><ul></ul></li><li><span>Acer</span><ul></ul></li></ul></li><li><span>Desktops</span><ul></ul></li></ul></li></ul></li><li><span>Home</span><ul></ul></li></ul>
This shall be a working example using recursion, not tested though:
Define the array
$main_array = Array
(
'10' => Array
(
'name' => 'Products'
'children' => Array
(
'12' => Array
(
'name' => 'Laptop',
'children' => Array
(
'13' => Array
(
'name' => 'Dell',
),
'14' => Array
(
'name' => 'Acer',
)
)
)
'14' => Array
(
'name' => 'Desktop',
'children' => Array
(
'15' => Array
(
'name' => 'Sony',
),
'16' => Array
(
'name' => 'Apple',
)
)
),
)
)
)
Create and call the function :
function createList($main_topics)
{
if($main_topics == null || sizeof($main_topics) <= 0)
{
return '';
}
$list = '<ul>';
foreach($main_topics as $k_main_topics => $v_main_topics )
{
$list .= '<li id="' . $k_main_topics'"> '. $v_main_topics['name'] . ' ' . createList(isset($v_main_topics["children"]) ? $v_main_topics["children"] : null) . '</li>' ;
}
$list .= '</ul>';
return $list;
}
echo createList($main_array);

How to loop through this complex associative array? [duplicate]

This question already has answers here:
How can I access an array/object?
(6 answers)
Closed 11 months ago.
I have an array named as $reports. Which is in following format. When i tried to see using print_r($reports) in my view file.
Array
(
[x] => Array
(
[A] => Array
(
[0] => Channel1 - 1 Stations
[1] => n
[2] => 1
[3] => 2012-11-02 11:30:00
[4] => 60
[5] => 20
[6] => 0
[7] => 18
[8] => 602
[9] => 540
[10] => Array
(
[0] => Array
(
[1] => Whirlpool Ice Magic 30.sec Tamil
[2] => 0
[3] => 20
[4] => 0
[5] => 18
[6] => 602
[7] => 540
)
)
)
)
)
I just showed here one x array like that i have so many arrays i want to loop through all of them. can please any one give me an idea how to do it.
$ary = array
("x" => array(
"A" => array
(
0 => "Channel1 - 1 Stations",
1 => "n",
2 => 1,
3 => "2012-11-02 11:30:00",
4 => 60,
5 => 20,
6 => 0,
7 => 18,
8 => 602,
9 => 540,
10 => array
(
0 => array
(
1 => "Whirlpool Ice Magic 30.sec Tamil",
2 => 0,
3 => 20,
4 => 0,
5 => 18,
6 => 602,
7 => 540,
)
)
),
));
function fetchArray($ary, $level = 0)
{
if (is_array($ary))
{
$pad = $level * 25;
foreach ($ary as $key => $val)
{
if (is_array($val))
{
echo "<div style='padding-left:" . $pad . "px'>" . $key . " = Array</div>";
$level++;
fetchArray($val, $level);
}
else
{
echo "<div style='padding-left:" . $pad . "px'>" . $key . " => " . $val . "</div>";
}
}
}
}
fetchArray($ary, 0);
Try this..
<?php
$array = ....;
foreach($array as $value)
{
foreach($value as $valueInner)
{
if(is_array($valueInner))
{
foreach($valueInner as $valueInner2)
{
foreach($valueInner2 as $valueInner3)
{
echo $valueInner3."\n";
}
}
}
else
{
echo $valueInner."\n";
}
}
}
?>
Generic example.
// your data
$a = array(
'a',
'b',
array (
'c',
'd',
array ('e','f')
)
);
// your recursive function
function echo_row($x) {
if (is_array($x)) {
// if is an array calls the recursive function over the new array
foreach ($x as $e) {
echo_row($e);
}
} else {
// prints a row, change to your table html
echo $x . "<br>";
}
}
// execute the function
echo_row($a);
// results
a
b
c
d
e
f
something like that
foreach($reports as $report) {
foreach($report as $element) {
//$element[3] would give you 2012-11-02 11:30:00
if(is_array($element) {
foreach($element as $x) {
foreach($x as $y) {
//$y[1] would give you Whirlpool Ice Magic 30.sec Tamil
}
}
}
}
}
foreach($reports as $key1=>$val1)
{
foreach($val1 as $key2=>$val2)
{
foreach($val2 as $key3=>$val3)
{
echo $val;
}
}
}
i have created a php function, that will extract a nested array into new basic array:
function extractArray($nested_array,&$new_array)
{
foreach($nested_array as $key => $val)
{
if(is_array($val)) extractArray($val,$new_array);
else $new_array[$key] = $val;
}
}
Something like:
array_walk_recursive($reports,
create_function('$e','if (is_scalar($e)) printf("%s\n",$e);'));

PHP: reorder array to show hierarchy

How can I turn the first array in to the second one? The goal is to create an array that shows the hierarchy, based on location_id and parent_id. Each location_name should be in an array of which the key is its parent_id.
Ignore the values I gave to location_name. No value for parent_id == NULL, these are the top level items.
First array:
Array
(
[0] => stdClass Object
(
[location_id] => 1
[location_name] => Town 1
[parent_id] =>
)
[1] => stdClass Object
(
[location_id] => 2
[location_name] => Town 1.1
[parent_id] =>
)
[2] => stdClass Object
(
[location_id] => 3
[location_name] => Town 1.2
[parent_id] => 1
)
[3] => stdClass Object
(
[location_id] => 4
[location_name] => Town 1.3
[parent_id] => 1
)
[4] => stdClass Object
(
[location_id] => 5
[location_name] => town 1.1.1
[parent_id] => 2
)
[5] => stdClass Object
(
[location_id] => 6
[location_name] => Town 1.1.2
[parent_id] => 3
)
);
Resulting array should be:
Array(
'Town 1' = array(
'town 1.2',
'town 1.3' = array(
'town 1.1.2'
)
),
'Town 2' = array(
'town 1.1.1'
)
);
EDIT: working solution based on Rijk's answer
function _order_locs($parent, $array)
{
$return = array();
foreach ( $array as $town )
{
if ( $town->parent_id == $parent )
{
$set = $this->_order_locs( $town->location_id, $array );
if( $this->_menu_is_parent($town->location_id, $array) ) $return[$town->location_name] = $set;
else $return[] = $town->location_name;
}
}
return $return;
}
function _menu_is_parent($id, $array)
{
foreach( $array as $a )
{
if( $a->parent_id == $id ) return TRUE;
}
}
You have to loop through it, using a recursive function (one that calls itself):
function getChilds( $parent, $array ) {
$return = array();
foreach ( $array as $town ) {
if ( $town['location_id'] == $parent ) {
$return[] = array(
'name' => $town['location_name'],
'childs' => getChilds( $town['location_id'], $array )
);
}
}
return $return;
}
$towns_tree = getChilds( 0, $towns );
Might not work right off the bat, but that gives you a nice oppurtunity to play with the code and get familiar with this concept ;)
Here is some code that will more or less do what you need. You will have to tweak it to your liking.
<?php
Class Node {
public $id;
public $parent_id;
public $value;
public $children;
public $depth;
function __construct($id, $parent_id, $value) {
$this->id = $id;
$this->parent_id = $parent_id;
$this->value = $value;
$this->children = array();
$this->depth = 0;
}
function add_child(Node $new_child) {
if ($new_child->parent_id == $this->id) {
$this->children[$new_child->id] = $new_child;
$this->children[$new_child->id]->depth = $this->depth + 1;
} else {
foreach ($this->children as $child) {
$child->add_child($new_child);
}
}
}
function to_array() {
if (count($this->children) > 0) {
$arr = array();
foreach ($this->children as $child) {
array_push($arr, $child->to_array());
}
return array($this->value => $arr);
} else {
return $this->value;
}
}
function str() {
echo str_repeat(" ", $this->depth) . $this->value . "\n";
foreach ($this->children as $child) {
$child->str();
}
}
}
?>
Here is some sample code to test it with:
<?php
$arr = Array(
array('location_id' => 1,
'location_name' => 'Town 1',
'parent_id' => 0),
array('location_id' => 2,
'location_name' => 'Town 1.1',
'parent_id' => 0),
array('location_id' => 3,
'location_name' => 'Town 1.2',
'parent_id' => 1),
array('location_id' => 4,
'location_name' => 'Town 1.3',
'parent_id' => 1),
array('location_id' => 5,
'location_name' => 'Town 1.1.1',
'parent_id' => 2),
array('location_id' => 6,
'location_name' => 'Town 1.1.2',
'parent_id' => 3)
);
$root = new Node(0, 0, 'root');
foreach ($arr as $item) {
$node = new Node($item['location_id'],
$item['parent_id'],
$item['location_name']);
$root->add_child($node);
}
$tree = $root->to_array();
$tree = $tree['root'];
var_dump($tree);
?>

Categories