I want to traverse this array and display, 'comment' as bullet points.
Array
(
[1] => Array
(
[id] => 1
[comment] => a
[parent_id] => 0
[children] => Array
(
[3] => Array
(
[id] => 3
[comment] => c
[parent_id] => 1
[depth] => 0
[child_count] => 0
[children] =>
)
[4] => Array
(
[id] => 4
[comment] => d
[parent_id] => 1
[depth] => 0
[child_count] => 0
[children] =>
)
)
[depth] => 1
[child_count] => 2
)
[2] => Array
(
[id] => 2
[comment] => b
[parent_id] => 0
[children] => Array
(
[5] => Array
(
[id] => 5
[comment] => e
[parent_id] => 2
[children] => Array
(
[7] => Array
(
[id] => 7
[comment] => g
[parent_id] => 5
[children] => Array
(
[8] => Array
(
[id] => 8
[comment] => h
[parent_id] => 7
[children] => Array
(
[9] => Array
(
[id] => 8
[comment] => h
[parent_id] => 8
[children] => Array
(
[10] => Array
(
[id] => 8
[comment] => h
[parent_id] => 9
[depth] => 0
[child_count] => 0
[children] =>
)
)
[depth] => 1
[child_count] => 1
)
)
[depth] => 2
[child_count] => 1
)
)
[depth] => 3
[child_count] => 1
)
)
[depth] => 4
[child_count] => 1
)
[6] => Array
(
[id] => 6
[comment] => f
[parent_id] => 2
[depth] => 0
[child_count] => 0
[children] =>
)
)
[depth] => 5
[child_count] => 2
)
)
You need a little bit of recursion
function traverse_array($array)
{
echo '<ul>';
foreach($array as $element)
{
echo '<li>';
if(isset($element['comment']))
{
echo $element['comment'];
}
if(is_array($element['children']) && count($element['children']) > 0)
{
traverse_array($element['children']);
}
echo '</li>';
}
echo '</ul>';
}
traverse_array($the_big_array);
Here you go, my hierTree() function by default prints nested ul or ol lists, for an undetermined depth of nested arrays, this function will work out of the box for the example array provided in your question.
function hierTree($arr, $tag = 'ul', $key = 'comment', $lvl = 0)
{
$tabs = (!$lvl)? '': str_repeat("\t", $lvl);
reset($arr);
echo "$tabs<$tag>\n";
while (list(, $v) = each($arr))
{
echo "$tabs\t<li>";
echo "{$v[$key]}";
if (count($v['children']))
{
echo "\n";
hierTree($v['children'], $tag, $key, $lvl +1);
echo "$tabs\t";
}
echo "</li>\n";
}
echo "$tabs</$tag>\n";
}
hierTree($tree);
The output of this function will be nicely indented for it to be easily readable.
Also, If you do hierTree($tree, 'ol'); you will get an ordered list. Id you do hierTree($tree, 'ol', 'id'); You will get an ordered tree and the id field will be print instead of the default comment one.
Inserting classes.
If you want to have different classes per list element so you can more easily style on CSS. (although I would recomment to use CSS direct descendant selectors (“>”))
function hierTree($arr, $tag = 'ul', $key = 'comment', $lvl = 0)
{
$tabs = (!$lvl)? '': str_repeat("\t", $lvl);
reset($arr);
echo "$tabs<$tag class=\"depth$lvl\">\n"; // ← The change is there.
while (list(, $v) = each($arr))
{
echo "$tabs\t<li>";
echo "{$v[$key]}";
if (count($v['children']))
{
echo "\n";
hierTree($v['children'], $tag, $key, $lvl +1);
echo "$tabs\t";
}
echo "</li>\n";
}
echo "$tabs</$tag>\n";
}
This slightly modified version will print a depthN class per list element.
So you can then target their *LI*s by a simple CSS rule such as ul.depth1 > li { ....
Related
my array is looking like
Array
(
[0] => Array
(
[id] => 1
[parent_id] => 0
[title] => Mobiles & Tablets
[childs] => Array
(
[0] => Array
(
[id] => 10
[parent_id] => 1
[title] => Mobile Phone
)
)
)
[1] => Array
(
[id] => 5
[parent_id] => 0
[title] => Mobile Phones
[childs] => Array
(
[0] => Array
(
[id] => 2
[parent_id] => 5
[title] => Moto G
[childs] => Array
(
[0] => Array
(
[id] => 3
[parent_id] => 2
[title] => Android
)
)
)
[1] => Array
(
[id] => 4
[parent_id] => 5
[title] => Iphone
)
)
)
[2] => Array
(
[id] => 6
[parent_id] => 0
[title] => test
)
[3] => Array
(
[id] => 7
[parent_id] => 0
[title] => Men's Fashion
[childs] => Array
(
[0] => Array
(
[id] => 12
[parent_id] => 7
[title] => Clothing
[childs] => Array
(
[0] => Array
(
[id] => 8
[parent_id] => 12
[title] => Jeans
)
)
)
)
)
[4] => Array
(
[id] => 9
[parent_id] => 0
[title] => test
)
)
i write php code for extract Array.
public $string = '';
public $result = array();
public function getCategoryListsTree( array $items ){
$this->createCategoryExtractNode($items);
echo '<pre>';
print_r($this->result);
exit;
}
public function createCategoryExtractNode(array $items)
{
foreach ($items as $key => $value) {
$this->string .= $value['title'].' > ';
if(isset($value['childs'])){
$this->string .= $this->createCategoryExtractNode($value['childs']);
}else{
$this->result[$value['id']] = trim($this->string,' > ');
$this->string = '';
}
}
}
The Output is
Array
(
[10] => Mobiles & Tablets > Mobile Phone
[3] => Mobile Phones > Moto G > Android
[4] => Iphone
[6] => test
[8] => Men's Fashion > Clothing > Jeans
[9] => test
)
I want output like
Array
(
[10] => Mobiles & Tablets > Mobile Phone
[3] => Mobile Phones > Moto G > Android
[4] => Mobile Phones > Iphone
[6] => test
[8] => Men's Fashion > Clothing > Jeans
[9] => test
)
please help
Thanks
Globals are evil, even if they are wrapped in a fancy OO style. $string is a local context for each createCategoryExtractNode invocation. This does the job:
public $result = array();
public function getCategoryListsTree( array $items ){
$this->createCategoryExtractNode($items);
echo '<pre>';
print_r($this->result);
exit;
}
public function createCategoryExtractNode(array $items, $carrier='')
{
foreach ($items as $key => $value) {
$string = $carrier . $value['title'].' > ';
if(isset($value['childs'])){
$this->createCategoryExtractNode($value['childs'], $string);
}else{
$this->result[$value['id']] = trim($string,' > ');
}
}
}
You need to keep current path in each moment, so lets add a respective property instead of string in your class definition:
public $path = [];
We push an element to path array on entering and pop array in the end. So path property array keeps current path to item. Path items are glued with ' > ' when reaching leaf node:
public function createCategoryExtractNode(array $items)
{
foreach ($items as $key => $value) {
array_push($this->path, $value['title']);
if (isset($value['childs'])) {
$this->string .= $this->createCategoryExtractNode($value['childs']);
} else {
$this->result[$value['id']] = implode(' > ', $this->path);
}
array_pop($this->path);
}
}
This also gets the job done:
public function createCategoryExtractNode(array $items, $breadcrumbs = array(), $level = 0)
{
foreach ($items as $key => $value) {
$breadcrumbs[$level] = $value['title'].' > ';
if(isset($value['childs'])){
$this->createCategoryExtractNode($value['childs'], $breadcrumbs, $level+1);
}else{
$this->string = implode('',$breadcrumbs);
$this->result[$value['id']] = trim($this->string,' > ');
$this->string = '';
}
}
}
First of all, sorry for my english.
I want to go through an array of any levels, but I want to go in the bottom level to up level and update a value of key recursively, but an example is better than a text:
this is my example code:
Array
(
[1] => Array
(
[ItemText] => Home
[ItemLink] => index.php
[count] => 0
[id] => 1
[ParentID] =>
[Children] => Array
(
[2] => Array
(
[ItemText] => Home Sub 1
[ItemLink] => somepage.php
[id] => 2
[count] => 0
[ParentID] => 1
[Children] => Array
(
[3] => Array
(
[ItemText] => Home Sub 2
[ItemLink] => somepage2.php
[id] => 3
[count] => 1
[ParentID] => 2
[Children] => Array
(
)
)
[4] => Array
(
[ItemText] => Contact
[ItemLink] => contact.php
[id] => 4
[count] => 1
[ParentID] => 2
[Children] => Array
(
)
)
)
)
)
)
)
note the count key in any level of array. Each level is a child of the "current" position. I need this:
Array
(
[1] => Array
(
[ItemText] => Home
[ItemLink] => index.php
[count] => **2**
[id] => 1
[ParentID] =>
[Children] => Array
(
[2] => Array
(
[ItemText] => Home Sub 1
[ItemLink] => somepage.php
[id] => 2
[count] => **2**
[ParentID] => 1
[Children] => Array
(
[3] => Array
(
[ItemText] => Home Sub 2
[ItemLink] => somepage2.php
[id] => 3
[count] => 1
[ParentID] => 2
[Children] => Array
(
)
)
[4] => Array
(
[ItemText] => Contact
[ItemLink] => contact.php
[id] => 4
[count] => 1
[ParentID] => 2
[Children] => Array
(
)
)
)
)
)
)
)
I want to accumulate and sum the count of all child in the current position and go through the prev level and accumulate again all count of the current level and that's to the up level.
I appreciate all your help. Thanks in advance.
EDIT
I adapted the function of #HamzaKubba to my needs and this works for me. I put this for those to require:
function explore(& $node) {
$count = 0;
if (count($node) > 0) {
foreach ($node as &$value) {
if (!isset($value['count']))
$value['count'] = 0;
if (count($value['Children']) > 0)
$value['count'] += explore($value['Children']);
$count += $value['count'];
}
}
return $count;
}
pseudoCode of general template:
function explore(node) {
foreach (child of node) {
explore(child)
}
// now that we're done with children, do logic/calculation here
doSomething(node)
}
pseudoCode of what you want (from what I understand):
function explore(node) {
foreach (child of node) {
node.count = node.count + explore(child)
}
return node.count
}
to correct your new code:
function explore_($node) {
if (!isset($node['count']))
$node['count'] = 0;
foreach ($node['Children'] as $child) {
$node['count'] = $node['count'] + explore_($child);
}
return $node['count'];
}
How do a delete all array entries where status equals 0?
That means: $array[1][3]; and $array[4];
Array
(
[1] => Array
(
[id] => 1
[parent_id] => 0
[status] => 2
[title] => bananer
[breadcrumb] => /bananer
[slug] => /bananer
[2] => Array
(
[id] => 2
[parent_id] => 1
[status] => 2
[title] => sub bananer
[breadcrumb] => /bananer/sub bananer
[slug] => /bananer/sub-bananer
)
[3] => Array
(
[id] => 3
[parent_id] => 1
[status] => 0
[title] => sub bananer 2
[breadcrumb] => /bananer/sub bananer 2
[slug] => /bananer/sub-bananer-2
)
)
[4] => Array
(
[id] => 4
[parent_id] => 0
[status] => 0
[title] => appelsin
[breadcrumb] => /appelsin
[slug] => /appelsin
[5] => Array
(
[id] => 5
[parent_id] => 4
[status] => 2
[title] => sub appelsin
[breadcrumb] => /appelsin/sub appelsin
[slug] => /appelsin/sub-appelsin
)
[6] => Array
(
[id] => 6
[parent_id] => 4
[status] => 2
[title] => sub appelsin 2
[breadcrumb] => /appelsin/sub appelsin 2
[slug] => /appelsin/sub-appelsin-2
)
)
)
Try this:
function deleteIt(&$array)
{
foreach($array as $key => &$value)
{
if (is_numeric($key)) deleteIt($value);
if (isset($value['status']) && !$value['status']) unset($array[$key]);
}
}
This runs through the array recursively while handing references down so that the original array is modified while deleting. Notice the & in the deleteIt function prototype and in the foreach.
Something like this may help
function parse($var)
{
foreach($var as $key => $val)
{
if( is_array($val) )
{
parse($val)
}
else
{
if($key == 'status' && $val ==0 )
{
// do something here
}
}
}
}
You can do something that's highly specialized such as:
function stripBadStatus($array) {
foreach($array as $k=>$arr) {
if($arr['status'] == 0) {
unset($array[$k]);
} else if(is_array($arr)) {
foreach($arr as $deepk=>$deeparr) {
if($deeparr['status'] == 0) {
unset($array[$k][$deepk]);
}
}
}
}
return $array;
}
I've been on this for two days now and I'm completely stuck. Google and SO couldn't help me further and I'm overlooking something....
This is what I want
Home
Typography
404 Page not found
The company
The company/Team
The company/Team/Rick
The company/Team/Rick/Opleiding
The company/Team//Rob
The company/Office
The company/Office/Contact
The company/Office/Route
This is my array
Array
(
[0] => Array
(
[id] => 55
[parent_id] => 0
[title] => Home
[sub] => Array
(
)
)
[1] => Array
(
[id] => 27
[parent_id] => 0
[title] => Typography
[sub] => Array
(
)
)
[2] => Array
(
[id] => 56
[parent_id] => 0
[title] => 404 Page not found
[sub] => Array
(
)
)
[3] => Array
(
[id] => 68
[parent_id] => 0
[title] => The company
[sub] => Array
(
[0] => Array
(
[id] => 73
[parent_id] => 68
[title] => Team
[sub] => Array
(
[0] => Array
(
[id] => 74
[parent_id] => 73
[title] => Rick
[sub] => Array
(
[0] => Array
(
[id] => 79
[parent_id] => 74
[title] => Opleiding
[sub] => Array
(
)
)
)
)
[1] => Array
(
[id] => 75
[parent_id] => 73
[title] => Rob
[sub] => Array
(
)
)
)
)
[1] => Array
(
[id] => 76
[parent_id] => 68
[title] => Office
[sub] => Array
(
[0] => Array
(
[id] => 78
[parent_id] => 76
[title] => Contact
[sub] => Array
(
)
)
[1] => Array
(
[id] => 77
[parent_id] => 76
[title] => Route
[sub] => Array
(
)
)
)
)
)
)
)
This is what I have so far
public function BuildTitle($array, &$parents = null)
{
$html = '';
foreach($array as $page)
{
if($page['parent_id'] != 0)
{
$html .= $parents.'/'.$page['title'].'<br/>';
$parents = $parents.'/'.$page['title'];
}
else
{
$html .= $page['title'].'<br/>';
$parents = $page['title'];
}
$html .= $this->BuildTitle($page['sub'], $parents);
}
return $html;
}
And that returns
Home
Typography
404 Page not found
The company
The company/Team
The company/Team/Rick
The company/Team/Rick/Opleiding
The company/Team/Rick/Opleiding/Rob
The company/Team/Rick/Opleiding/Rob/Office
The company/Team/Rick/Opleiding/Rob/Office/Contact
The company/Team/Rick/Opleiding/Rob/Office/Contact/Route
Parent/child relations are unlimited. What am I doing wrong/missing? Thanks in advance!
You're modifying the same $parents value in every iteration. So, as long as the parent isn't 0, it just appends the current child to whatever the path is.
Imagine for instance you had the following scenario:
foo
bar
baz
When processing foo, it'd start with $parents = 'foo'.
It then goes through each of the children, updating $parents:
bar makes $parents = $parents . '/' . $page['title'] = 'foo' . '/' . 'bar' = 'foo/bar'.
baz makes $parents = $parents . '/' . $page['title'] = 'foo/bar' . '/' . 'bar' = 'foo/bar/baz'.
What you want is this:
public function BuildTitle($array, $parents = null)
{
$html = '';
foreach($array as $page)
{
if($page['parent_id'] != 0)
{
$html .= $parents.'/'.$page['title'].'<br/>';
$new_parents = $parents.'/'.$page['title'];
}
else
{
$html .= $page['title'].'<br/>';
$new_parents = $page['title'];
}
$html .= $this->BuildTitle($page['sub'], $new_parents);
}
return $html;
}
How do I rearrange the following array
[0] => Array
(
[id] => 1
[parent_id] => 0
[name] => Accueil
)
[1] => Array
(
[id] => 2
[parent_id] => 0
[name] => Exposants
)
[2] => Array
(
[id] => 3
[parent_id] => 0
[name] => Visiteurs
)
[3] => Array
(
[id] => 4
[parent_id] => 0
[name] => Medias
)
[4] => Array
(
[id] => 5
[parent_id] => 0
[name] => Activités
)
[5] => Array
(
[id] => 6
[parent_id] => 1
[name] => Contact
)
[6] => Array
(
[id] => 7
[parent_id] => 3
[name] => Partenaires
)
[7] => Array
(
[id] => 8
[parent_id] => 2
[name] => News
)
So I come up with an array that reflects the hierarchy as shown by the id and parent_id fields? The array key is the ID field of array elements are parents. Inside this array is each time a child array that has its ID field as the key. Sample:
[1] => Array
(
[name] => Accueil
[children] => array(
[0] => bla,
[3] => bla2
)
)
[2] => Array
(
[name] => Something
[children] => array(
[4] => bla3,
)
)
Works for any depth and allows children to precede parents:
<?php
$p = array(0 => array());
foreach($nodes as $n)
{
$pid = $n['parent_id'];
$id = $n['id'];
if (!isset($p[$pid]))
$p[$pid] = array('child' => array());
if (isset($p[$id]))
$child = &$p[$id]['child'];
else
$child = array();
$p[$id] = $n;
$p[$id]['child'] = &$child;
unset($p[$id]['parent_id']);
unset($child);
$p[$pid]['child'][] = &$p[$id];
}
$nodes = $p['0']['child'];
unset($p);
?>
Use var_dump on the $nodes result to see the structure. It is close to what you suggested. The major difference is that the keys are not the ids.
You could make this more DRY, but it's a quick and dirty way to handle it. Also, you could remove 6 lines if you could guarantee that each child record has a valid parent record and that the valid parent record precedes the child record in the original array.
$sorted = array();
foreach( $orig_ary as $item ) {
if ( $item['parent_id'] === 0 ) {
if ( !array_key_exists( $item['id'], $sorted ) ) {
$sorted[ $item['id'] ] = array(
'name' => '',
'children' => array()
);
}
$sorted[ $item['id'] ]['name'] = $item['name'];
} else {
if ( !array_key_exists( $item['parent_id'], $sorted ) ) {
$sorted[ $item['parent_id'] ] = array(
'name' => '',
'children' => array()
);
}
$sorted[ $item['parent_id'] ]['children'][ $item['id'] ] = $item['name'];
}
}