I have an array which has id and parent_id like this
$element=new array(
[0]=>array(1,0), --------level 1
[1]=>array(2,0), -------level 1
[2]=>array(3,1), ------level 2
[3]=>array(4,1), ------level 2
[4]=>array(5,1), ------level 2
[5]=>array(6,2), ------level 2
[6]=>array(7,3), ------level 3
[7]=>array(8,2), ------level 2
[8]=>array(9,3), ------level 3
[9]=>array(10,6), ------level 3
[10]=>array(11,6), ------level 3
);
this is my array, in inner array first element is id of the array and second element is id of parent element.
now i want to find level of each element from root.
assume zero (0) is root element.
You can use a recursive approach. I'm assuming that the item at index N in the outer array always has id N+1. If not, you'll first have to search for the item with the matching id, but otherwise the rest of the logic should be the same.
<?php
function findLevel($id) {
$item = $element[$id-1]; //If my assumption (above) is incorrect,
// you'll need to replace this with an appropriate
// search function, which could be as simple as
// a loop through the array.
$parent = $item[1];
if ($parent == 0) {
//Parent is root. Assuming root is level 0, then
// this item is level 1.
return 1;
}
return 1 + findLevel($parent);
?>
$parent_id = n;
$level = 0;
while($parent_id != 0){
$inner_array = $element[$parent_id];
$parent_id = $inner_array[1];
$level ++;
}
Let's try this, you initially set $parent_id to the index of the $element array you want to know the level.
Make sure each level can be calculated
Related
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.
in case of tl;dr: setting up array with references and then changing a copy of said array still preserves references and elements of all copies are changed at the same time. Need a workaround of replacing reference with the value that it points to.
I'm getting a complicated problem with using references in PHP Arrays :(
I have a flat array of unique elements with two properties: order and level.
Order represents element's order number from 1 to n in like table of contents way. Level represents which level "subchapter" the element is.
Example:
First brackets are element IDs which are random but unique:
[1][order:1][level:1]
----[7][order:2][level:2]
----[4][order:3][level:2]
---- ----[2][order:4][level:3]
[3][order:5][level:1]
[6][order:6][level:1]
----[5][order:7][level:2]
.
.
.
Remember, this is flat array of elements, above its just a visual representation.
Now I have tried to put them into array of form:
[1][children] => [
[7],
[4][children] => [
[2]
]
]
[3],
[6][children] => [
[5]
]
Which would represent a tree structure -ish..
I do this by first ordering them by order:
foreach($elements as $element){
$ordered_elements[$element['order']] = $element;
}
Then I shift each element under the correct parent:
foreach($ordered_elements as &$child){
if($child['level'] > 1){
$ordered_elements[$last_parent[$child['level']-1]]['children'][$child['content_id']] = &$child; // I think this is problematic line!!!
}
$last_parent[$child['level']] = $child['sort_order'];
}
Some of the elements stayed on root (first) level that shouldnt be there:
foreach($ordered_elements as &$child){
if($child['level'] == 1){
$ordered_elements[$child['content_id']] = $child;
}
unset($ordered_elements[$child['sort_order']]);
}
Now when this is done, the template array is ready. Now I start getting some data from query with element_id and user_id.
I want to set up a new table "users" that would have this previously made array for each user and I would be able to change its elements per user.
users[1]['elements'] = $ordered_elements;
users[2]['elements'] = $ordered_elements;
This function should return element by reference from user's own pool of elements, so we can change it directly into the users[x]['elements'][x]:
function &get_element_from_array(&$array, $searchValue){
$status = false;
foreach($array as $id => &$subtree) {
if ($id === $searchValue) {
return $subtree;
}
if (isset($subtree['children'])) {
$subsearch = &$this->get_element_from_array($subtree['children'], $searchValue);
if ($subsearch != false) {
return $subsearch;
}
}
}
return $status;
}
That means If i want to change element 5 from user 2 I need to call it like this:
$element = &get_element_from_array(users[2]['elements'], 5);
$element['visited'] = true;
This is where the problem occurs: I have just changed this element in user2 AND user1 array of elements.
I hope I didnt wrote this thing too long, was going for good explanation.
I have a table of data as such:
id | item | parent_id
1 item 1 0
2 item 2 0
3 item 3 2
4 item 4 3
5 item 5 1
...
The id is autoincrementing, and the parent_id reflects the id on the left. You may have come accross a database table design like this before.
The parent_id is not sequential as you can see.
I need to get this table data into an array in the format where all parents become a potential heading with their children underneath.
So I am looking at a structure like this:
Item 1
Item 5
Item 2
Item 3
Item 4
etc
In PHP I need an array structure that can display the above. But I am having a serious brain fart!
Can anyone help me with the array structure?
you may write somethin like this:
$a = Array(item1 => Array(item5), item2 => Array(item3 => Array(item4)))
or
$a = Array(item1 => parentid, item2 => parentid2 ....)
in the first example one item is the key for all ist children stored in the Array, in the other example all items are stored using an item key and an int value. this int value is the key for the parent item. which method you use depends on what you want to do with this Array. maybe both of my ideas are not good enough for your Needs. if thats the case, tell me what you need.
First of all, i will suggest you to read this, it's very useful for hierarchical structured data and there are available queries which will help you to get parents, children, etc ... and so and so.
Now to answer your question, try this :
$result = array();
while($data = mysql_fetch_assoc($query)) {
$id = $data['id'];
$parent = $data['parent_id'];
$keys = array_keys($result);
if(in_array($parent, $keys)) {
$result[$parent] = array_merge($result[$parent], array($id => $data['item']));
} else {
$result = array_merge($result, array($id => $data['item']));
}
}
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.
I have a question about associative arrays in php.
I have following array in which there are two items named 4 and 2 respectively.
$items = array(4,2);
Now i want to associate each item's quantity to it which can be done as follows:
$items['4']=23;
$items['2']=0;
which means that there are 23, 'item 4s' and no 'item 2'.
But I sometimes don't know in advance what is there in the $items so i want to associate quantity on basis of location. I wanted to do something like associate 23 to whatever is there on the zero location of the item array:
$items['items[0]']=23;
This of course did not work because its not the right way to extract whatever is placed on the zero location of items. Can anyone please tell me how do i do that?
You are confusing in the use of item and items. I imagine you have both an item array and an items array, else things can easily get hairy.
Anyhow, you just refer to it as a variable, not as a string:
$items[$item[0]] = 23;
Let me get this straight. So you start with an array that looks like this:
$items = array( 0 => 4, 1 => 2 )
And you want to end up with an array that looks like this: ?!
$items = array( 0 => 4, 1 => 2, 2 => 0, 4 => 23 )
I think you should use your array as a kind of "map". The item number is your key, and the quantity your value.
By calling
$items = array(4,2);
you create
$items[0] = 4;
$items[1] = 2;
but you want to use the 4 and 2 as a key in your array. So you should instead use
$items = array( 4 => false, 2 => false );
where false stands for an item that has not yet a quantity associated (could also be e.g. -1).
This creates
$items[2] = false;
$items[4] = false;
When using false, you can check for not assigned values by calling
if ($items[4] === false) {
echo "No quantity set!";
}
And now the second step.. if you want to assign the item #4 a quantity of 23, just call
$items[4] = 23;
So I don't think you will want to rely on the order inside your array..