Array key exists in multidimensional array - php

I'm trying to arrange a group of pages in to an array and place them depending on their parent id number. If the parent id is 0 I would like it to be placed in the array as an array like so...
$get_pages = 'DATABASE QUERY'
$sorted = array()
foreach($get_pages as $k => $obj) {
if(!$obj->parent_id) {
$sorted[$obj->parent_id] = array();
}
}
But if the parent id is set I'd like to place it in to the relevant array, again as an array like so...
$get_pages = 'DATABASE QUERY'
$sorted = array()
foreach($get_pages as $k => $obj) {
if(!$obj->parent_id) {
$sorted[$obj->id] = array();
} else if($obj->parent_id) {
$sorted[$obj->parent_id][$obj->id] = array();
}
}
This is where I begin to have a problem. If I have a 3rd element that needs to be inserted to the 2nd dimension of an array, or even a 4th element that needs inserting in the 3rd dimension I have no way of checking if that array key exists. So what I can't figure out is how to detect if an array key exists after the 1st dimension and if it does where it is so I can place the new element.
Here is an example of my Database Table
id page_name parent_id
1 Products 0
2 Chairs 1
3 Tables 1
4 Green Chairs 2
5 Large Green Chair 4
6 About Us 0
Here is an example of the output I'd like to get, if there is a better way to do this I'm open for suggestions.
Array([1]=>Array([2] => Array([4] => Array([5] => Array())), [3] => Array()), 6 => Array())
Thanks in advanced!

Well, essentially you are building a tree so one of the ways to go is with recursion:
// This function takes an array for a certain level and inserts all of the
// child nodes into it (then going to build each child node as a parent for
// its respective children):
function addChildren( &$get_pages, &$parentArr, $parentId = 0 )
{
foreach ( $get_pages as $page )
{
// Is the current node a child of the parent we are currently populating?
if ( $page->parent_id == $parentId )
{
// Is there an array for the current parent?
if ( !isset( $parentArr[ $page->id ] ) )
{
// Nop, create one so the current parent's children can
// be inserted into it.
$parentArr[ $page->id ] = array();
}
// Call the function from within itself to populate the next level
// in the array:
addChildren( $get_pages, $parentArr[ $page->id ], $page->id );
}
}
}
$result = array();
addChildren( $get_pages, $result );
print_r($result);
This is not the most efficient way to go but for a small number of pages & hierarchies you should be fine.

Related

Paginate Tree Array

I am looking at trying to build pagination method for an array. I have an array something like below. Before you suggest making the pagination work for sql query, I have already done so and it did work for a flat array but a requirement is having this multidimensional tree array.
array = (
item_id = 5,
parent_id = 0,
children = array(
array(
item_id = 20,
parent_id = 5,
children = array(
array(
item_id = 24,
parent_id = 20
),
array(
item_id = 24,
parent_id = 20
)
)
)
)
);
What methods that I can find don't seem to work with such an array since array_slice will only work on the first level of the array and doesn't take into consideration the children levels.
/*
$root =
[
'id' => 1,
'children' => [...]
]
$queue[] = $root
$visiteds[] = $root
while ($queue){
$current = array_shift($queue);
// do whatever with the current ex: echo $current."<br>"
if $current has children {
foreach child {
if ($child NOT in $visiteds) { // $child not visited before
$visiteds[] = $child // mark as visited
$queue[] = $child // add to queue
// do whatever with the child ex: echo $child ."<br>"
}
}
}
}
*/
Note: if you want to visit exactly same children as required (for example 2 exactly same child must be visited twice then, remove $visiteds related parts. In this case be careful that your graph structure must not have cycling.)
You may consider to read about Graph Theory, Breadth First Search algorithm, Depth First Search algorithm.

Convert multi-dimensional array into matrix-like array

I have the following array:
$array = array(
array("2018","2019"),
"Jan",
array("France","Germany")
);
I need a matrix that crosses all the elements of the array; e.g:
array(
array("2018","Jan","France"),
array("2018","Jan","Germany"),
array("2019","Jan","France"),
array("2019","Jan","Germany")
);
meaning, 2 x 2 x 1 arrays
but this can be that I have more elements that are or are not arrays then:
$array = array(
array("2018","2019"),
"Jan",
array("France","Germany"),
array("prod1","prod2","prod3"),
'Act'
);
In this case I would get 2 x 2 x 1 x 4 x 1 arrays in the end.
Any idea on how to achieve this?
Is that what you are looking for ?
$dst = array(array());
foreach ($array as $idx => $val) {
foreach ($dst as $tmp_idx => $tmp_array) {
if (is_array($val)) {
foreach ($val as $sub_idx => $sub_val) {
$dst[] = array_merge($dst[$tmp_idx], array(count($dst[$tmp_idx]) => $sub_val));
}
} else {
$dst[] = array_merge($dst[$tmp_idx], array(count($dst[$tmp_idx]) => $val));
}
unset($dst[$tmp_idx]);
}
}
I declare the array with an empty array in it.
A first foreach iterates through the main array to access all the categories, whatever their number.
A second foreach iterates through the result array.
A third foreach - or not, depending if the category contains several or a single entry - iterates through each entry of the current category and merges an array containing only that current category in the result currently iterated on (from $dst). The merge is pushed into the result array. The result stored in $dst are assumed to be temporary and will be copied and completed with each new value, making them progressively contain one entry from each category.
At the end of each iteration on $dst, the current temporary result is removed from the array since it has no purpose : if the foreach iterated on it, that means that it was incomplete.
At the end, the only entries in $dst that remain are these who weren't iterated on, meaning that every entry from each category were considered when they were created, meaning that they are complete.
I'm available for any clarification may the need arise.

Recursive function to generate flat array from hierarchical array

What I've tried to do for the past hour is a function that will let me generate a flat array of the same pages, but with the children having their parents title before them
what I could do so far is get 1 level of the parents, I need the logic behind this and I can do the code, the main point is to have an array to fetch in select menu
i.e:
Parent
parent / Sub 1
Parent / Sub 1 / Sub 2
Parent 2
parent 2 / Sub 1
Parent 2 / Sub 1 / Sub 2
My array looks like this :
Array (
[0] => Array (
[object]=>menuObject
[title]=>title
[parent_id]=>parent_id
[children]=>array(
[0] => Array (
[object]=>menuObject
[title]=>title
[parent_id]=>parent_id
[children]=>''
)
)
)
);
the array I need will look like:
Array(
[14]=>'parent / sub / sub 1'
//[ID]=>[Title]
)
Well, after pretty long time I figured out a way to do it with 2 functions,
the first to flatten the array, and the other to find out the path, though I had to Query the DB to make it
public function parseSelectArray($tree)
{
$return=array();
foreach ($tree as $key => $value) {
//The other function call to create the path
$return[$key]=Controller_Admin_Pages::createPath($key);
}
return empty($return) ? null : $return;
}
public function createPath($id) {
//Query the page, though I could get the value from the array.
$page=Model_Page::find($id);
if($page->idparent == 0) {
$name = $page->title;
return $name;
} else {
$name = $page->title;
return Controller_Admin_Pages::createPath($page->idparent). " / ".$name;
}
}

Zend framework foreach loop stop ate the first iteration

I'm actually working on ZF. I have a category table with which, I want to create a tree in order to get display the data as below :
Category
--Sub cat 1
--Sub cat 2
----Su sub cat 1
Another Category
--Sub cat 1
//...etc...
I'm using the fetchAll method to get all my data. Everyting works fine. But then I'm now trying to create my tree into a double foreach loop as below :
$tree = array();
foreach($data as $parent){
$tree[$parent->name] = array();
foreach($data as $child){
if($child->parent_id == $parent->id){
$tree[$parent->name][] = $child->name;
}
}
}
The problem is that the loop stop after the main loop first iteration so I'm just getting the first parent and it's sub category but it does not continue to the second parent.
My database table as the following fields :
id, name, parent_id
Any idea?
EDIT
Thanks to you Thibault, it did work using the good old for loop :
for($i=0;$i<count($data);$i++){
$tree[$data[$i]->name] = array();
for($j=0;$j<count($data);$j++){
if($data[$j]->parent_id == $data[$i]->id){
$tree[$data[$i]->name][] = $data[$j]->name;
}
}
}
You may have a conflict between the cursor of both $data variables.
You should use a copy of $data for the second foreach loop.
Or use for loops with $i and $j index, and call them via $data[$i] and $data[$j] to access the array, so the loops don't get messed up.
EDIT
Happy i could help, but after some research, i created this piece of code :
<?
class o {
public $id;
public $name;
public $parent_id;
function __construct($_id,$_name,$_parent) {
$this->id = $_id;
$this->name = $_name;
$this->parent_id = $_parent;
}
}
$data = array(
new o(1,'toto',0),
new o(2,'truc',1),
new o(3,'machin',1),
new o(4,'bidule',2),
new o(5,'titi',3),
new o(6,'tutu',3),
);
$tree = array();
foreach($data as $parent){
$tree[$parent->name] = array();
foreach($data as $child){
if($child->parent_id == $parent->id){
$tree[$parent->name][] = $child->name;
}
}
}
print_r($tree);
And your code works just fine :
(something must be wrong somewhere else ...)
Array
(
[toto] => Array
(
[0] => truc
[1] => machin
)
[truc] => Array
(
[0] => bidule
)
[machin] => Array
(
[0] => titi
[1] => tutu
)
[bidule] => Array
(
)
[titi] => Array
(
)
[tutu] => Array
(
)
)

PHP MySQL building a 3 Tier multi dimensional array

So I have my query, its returning results as expect all is swell, except today my designer through in a wrench. Which seems to be throwing me off my game a bit, maybe its cause Im to tired who knows, anyway..
I am to create a 3 tier array
primary category, sub category (which can have multiples per primary), and the item list per sub category which could be 1 to 100 items.
I've tried foreach, while, for loops. All typically starting with $final = array(); then the loop below that.
trying to build arrays like:
$final[$row['primary]][$row['sub']][] = $row['item]
$final[$row['primary]][$row['sub']] = $row['item]
I've tried defining them each as there own array to use array_push() on. And various other tactics and I am failing horribly. I need a fresh minded person to help me out here. From what type of loop would best suit my need to how I can construct my array(s) to build out according to plan.
The Desired outcome would be
array(
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
primary = array
(
sub = array
(
itemA,
itemB,
itemC
),
sub = array
(
itemA,
itemB,
itemC
),
),
)
Something like this during treatment of your request :
if (!array_key_exists($row['primary'], $final)) {
$final[$row['primary']] = array();
}
if (!array_key_exists($row['sub'], $final[$row['primary']])) {
$final[$row['primary']][$row['sub']] = array();
}
$final[$row['primary']][$row['sub']][] = $row['item'];
Something like this....
$final =
array(
'Primary1'=>array(
'Sub1'=>array("Item1", "Item2"),
'Sub2'=>array("Item3", "Item4")
),
'Primary2'=>array(
'Sub3'=>array("Item5", "Item6"),
'Sub4'=>array("Item7", "Item8")
),
);
You can do it using array_push but it's not that easy since you really want an associative array and array_push doesn't work well with keys. You could certainly use it to add items to your sub-elements
array_push($final['Primary1']['Sub1'], "Some New Item");
If I understand you correctly, you want to fetch a couple of db relations into an PHP Array.
This is some example code how you can resolve that:
<?php
$output = array();
$i = 0;
// DB Query
while($categories) { // $categories is an db result
$output[$i] = $categories;
$ii = 0;
// DB Query
while($subcategories) { // $subcategories is an db result
$output[$i]['subcategories'][$ii] = $subcategories;
$iii = 0;
// DB Query
while($items) { // $items is an db result
$output[$i]['subcategories'][$ii]['items'][$iii] = $items;
$iii++;
}
$ii++;
}
$i++;
}
print_r($output);
?>

Categories