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'];
}
Related
I need to assign parent ids to all the children of a multidimensional array in PHP.
Array
(
[expanded] => 1
[key] => root_1
[title] => root
[children] => Array
(
[0] => Array
(
[folder] => 1
[key] => 34
[title] => YAY PROJECTS
)
[1] => Array
(
[expanded] => 1
[folder] => 1
[key] => 6
[title] => Grand Designs Episodes
[children] => Array
(
[0] => Array
(
[folder] => 1
[key] => 8
[title] => AU Episodes
)
[1] => Array
(
[expanded] => 1
[folder] => 1
[key] => 7
[title] => UK Episodes
[children] => Array
(
[0] => Array
(
[folder] =>
[key] => 9
[title] => Start something
)
[1] => Array
(
[folder] =>
[key] => 2
[title] => Grand Designs Season 10
)
)
)
)
)
[2] => Array
(
[expanded] => 1
[folder] => 1
[key] => 5
[title] => Animations
[children] => Array
(
[0] => Array
(
[folder] =>
[key] => 4
[title] => Futurama Episode 191
)
[1] => Array
(
[folder] =>
[key] => 3
[title] => Miniscule Series 5 Ep 1
)
[2] => Array
(
[folder] =>
[key] => 1
[title] => The Simpsons Episode 459
)
)
)
[3] => Array
(
[folder] => 1
[key] => 11
[title] => Test Folder
)
[4] => Array
(
[folder] => 1
[key] => 10
[title] => Testing
)
)
)
At first I thought this would be fairly trivial, however my solution quickly falls apart assigning the wrong parent_ids.
public function generateParentIds(array $input, $parentId = 0)
{
$return = [];
foreach ($input as $key => $value) {
if (is_array($value)) {
$value = $this->generateParentIds($value, $parentId);
if (isset($value['children'])) {
$parentId = $value['key'];
}
if (!is_int($key)) {
$return['parent_id'] = $parentId;
}
}
$return[$key] = $value;
}
return $return;
}
I'm not sure whats going on, I did a lot of research but couldn't find any examples, so I'd be very grateful for some help.
Assuming that each child should get the immediate parent's key value as its parent_id, this should do what you want. Note that it modifies the array in place ($input is passed by reference to the function, and the foreach loop uses a reference to $child), rather than attempting to merge returned values.
function generateParentIds(&$input, $parentId = 0) {
$input['parent_id'] = $parentId;
if (isset($input['children'])) {
foreach ($input['children'] as &$child) {
generateParentIds($child, $input['key']);
}
}
}
generateParentIds($input);
Output is too long to show here but there's a demo at 3v4l.org
I am looking to convert a multi dimensional array into another multidimensional array using a recursive function.
Source array :
Array
(
[1] => Array
(
[id] => 1
[source_name] => kk56ca1d0f2378f
[company_id] => 1
[lft] => 1
[rgt] => 18
[parent_id] => 0
[children] => Array
(
[2] => Array
(
[id] => 2
[source_name] => kk56ca1d17f3f63
[company_id] => 1
[lft] => 2
[rgt] => 3
[parent_id] => 1
[children] => Array
(
)
)
[3] => Array
(
[id] => 3
[source_name] => kk56ca1d1ebe975
[company_id] => 1
[lft] => 4
[rgt] => 13
[parent_id] => 1
[children] => Array
(
[6] => Array
(
[id] => 6
[source_name] => kk56ca1fc882ac0
[company_id] => 1
[lft] => 5
[rgt] => 10
[parent_id] => 3
[children] => Array
(
)
)
)
)
)
)
)
which I need to get into the format of
Array
(
[0] => Array
(
[id] => 1
[text] => kk56ca1d0f2378f
[parent_id] => 0
[nodes] => Array
(
[0] => Array
(
[id] => 2
[text] => kk56ca1d17f3f63
[parent_id] => 1
[nodes] => Array
(
)
)
[1] => Array
(
[id] => 3
[text] => kk56ca1d1ebe975
[parent_id] => 1
[nodes] => Array
(
[0] => Array
(
[id] => 6
[text] => kk56ca1fc882ac0
[parent_id] => 3
[nodes] => Array
(
)
)
[1] => Array
(
[id] => 15
[text] => kk
[parent_id] => 3
[nodes] => Array
(
)
)
)
)
)
)
)
I have been trying for hours and getting nowhere with this. Any help would be really appreciated.
The source array has associative indexes (though they are numbers) and the destination array has numerical indexes. Besides this, just need to remove a few indexes and change names of a few.
EDIT :
Specific changes :
change index name source_name to text
change index name children to nodes
unset indexes lft, rgt, company_id
I do not have much experience with recursion so I have trying fruitlessly.
This is what I could come up with :
// pass array of nodes
function convert_array($from){
// this is a node
if(isset($from['source_name']))
{
$temp = array();
$temp['id'] = $from['id'];
convert_array($from['children']);
}
// this is an array of nodes
else
{
foreach($from as $arr)
{
$ret = convert_array($arr);
print_r($ret);
}
}
}
But I am not able to understand what data to be returned and how the new array builds up from the return values.
Here the working function:
function convert_array( $array )
{
$retval = array();
foreach( $array as $row )
{
$child = array();
$child['id'] = $row['id'];
$child['text'] = $row['source_name'];
$child['parent_id'] = $row['parent_id'];
if( count( $row['children'] ) )
{ $child['nodes'] = convert_array( $row['children'] ); }
else
{ $child['nodes'] = array(); }
$retval[] = $child;
}
return $retval;
}
3v4l demo
I think it is self-explanatory, BTW: we init an empty array ($retval), then we perform a foreach loop through all array argument: for each element, we init a new array and we add it id, source_name as text and parent_id; if the children index has elements, we perform a recursive call to fill nodes array index, otherwise we set it to empty array.
I need a help
This is my session array:
Array
(
[menu] =>
[id] => 3
[products] => Array
(
[0] => Array
(
[id] => 1
[name] => Produkt 1
[code] => 1
[varianta] =>
[pocet] => 1
[price] => 20
[pricepredtym] => 40
)
[1] => Array
(
[id] => 2
[name] => Produkt 1
[code] => 1
[varianta] =>
[pocet] => 1
[price] => 20
[pricepredtym] => 40
)
)
)
I would need about something like, if ($_GET [id] == $ _SESSION ['products'] [id]) and only change this "[pocet]" where [id] = 2
$_GET [id] = 2;
$pocet=5;
[1] => Array
(
[id] => 2
[name] => Produkt 1
[code] => 1
[varianta] =>
[pocet] => 5
[price] => 20
[pricepredtym] => 40
)
You could index your products array by product id. Then updating would be simply:
if(isset($_SESSION['products'][$prod_id])) {
$_SESSION['products'][$prod_id]['pocet'] = $pocet;
}
Otherwise, use a foreach loop:
foreach ($_SESSION['products'] as $i => $prod) {
if ($prod['id'] == $prod_id) {
$_SESSION['products'][$i]['pocet'] = $pocet;
break;
}
}
Compare your GET value with 2 and use it as key of SESSION array.
if ($_GET['id'] == '2'){
$_SESSION['products'][$_GET['id']]['pocet'] = '5';
}
This question already has answers here:
create array tree from array list [duplicate]
(9 answers)
Closed 9 years ago.
I have a multidimensional associative array "$nav_menus" looks like this:
Array
(
[0] => Array
(
[id] => 1
[menu_name] => Media
[parent_id] => 0
[submenus] => 1
)
[1] => Array
(
[id] => 2
[menu_name] => Movies
[parent_id] => 1
[submenus] => 1
)
[2] => Array
(
[id] => 3
[menu_name] => English Movies
[parent_id] => 2
[submenus] => 1
)
[3] => Array
(
[id] => 4
[menu_name] => Action
[parent_id] => 3
[submenus] => 1
)
)
What I'm trying to accomplish is to loop the array and whenever the value of the key ['parent_id'] doesn't equal 0 is to loop the array again and move this one into whatever menu the value of its ['id'] key equal that parent_id ... here is what I want $nav_menus to look like at the end
Array
(
[id] => 1
[menu_name] => Media
[parent_id] => 0
[submenus] => 1
[0] => Array
(
[id] => 2
[menu_name] => Movies
[parent_id] => 1
[submenus] => 1
[0] => Array
(
[id] => 3
[menu_name] =>English Movies
[parent_id] => 2
[submenus] => 1
[0] => Array
(
[id] => 4
[menu_name] => Action
[parent_id] => 3
[submenus] => 1
)
)
)
)
Here is what I was tried to accomplish it, but with no luck:
foreach($nav_menus as $k => $v){
if($v['parent_id'] !== 0){
$x = $v;
foreach($nav_menus as $key => $value){
if($value['id'] == $v['parent_id']){
unset($v);
array_push($value, $x);
break;
}
}
}
}
print_r($nav_menus);
It gives me the same original array without any change :( ... Any suggestions ?
Try this recursive function.
function array_new($arr1,$tot_count,$parent=0,$new_arr=array(),$global_count=0)
{
$count=0;
foreach($arr1 as $arr_res)
{
if($arr_res['parent_id']==$parent)
{
$new_arr['id'] = $arr_res['id'];
$new_arr['menu_name'] = $arr_res['menu_name'];
$new_arr['parent_id'] = $arr_res['parent_id'];
$new_arr['submenus'] = $arr_res['submenus'];
//DebugBreak();
if($global_count<$tot_count-1)
{ $global_count++;
$new_arr[$count] = array_new($arr1,$tot_count,$arr_res['id'],$new_arr,$global_count);
$count++;
}
}
}
return $new_arr;
}
'$arr_unformated' is your array which you have now.
$tot_count = count($arr_unformated);
$arrnew = array_new($arr_unformated,$tot_count);
And '$arrnew' is your desire array.
Essentially, I want to use the
$foo = new RecursiveIteratorIterator(new RecursiveArrayIterator($haystack));
Methodology, but instead of returning a flat array for foreach()ing through, keep the structure but only return a single great-grand-child node and it's parent nodes. Is this possible in PHP?
I've been tasked with optimising some of my company's (horrific) codebase. I found a function that recurses through an array, searching for a key. I can't replace this with a simple array_search() or array_key_exists() because the custom function also returns the parent nodes of the matched (found) key, instead of just a true or false.
How can I use RecursiveArrayIterator, RecursiveIteratorIterator or failing that, other built-in functions (i.e. as little custom code as possible) to return a matching node with it's parent tree from a search array? I want to get the fastest function possible, as currently this function spends 8 seconds executing 14 thousand times, hence my requirement to use built-in functions.
My existing attempt (below) is incredibly slow.
function search_in_array($needle, $haystack) {
$path = array();
$it = new RecursiveArrayIterator($haystack);
iterator_apply($it, 'traverse', array($it, $needle, &$path));
return $path;
}
function traverse($it, $needle, &$path) {
while($it->valid()) {
$key = $it->key();
$value = $it->current();
if(strcasecmp($value['id'], $needle) === 0) {
$path[] = $key;
return;
} else if($it->hasChildren()) {
$sub = null;
traverse($it->getChildren(), $needle, &$sub);
if($sub) {
$path[$key] = $sub;
}
}
$it->next();
}
}
Example output for $needle = TVALL would look like this:
Array (
[HOMECINEMA] => Array (
[children] => Array (
[HC-VISION] => Array (
[children] => Array (
[0] => TVALL
)
)
)
)
)
The search array looks something like this (sorry for the vast-ness). There are more than two top-level nodes, but I've truncated it for brevity:
Array(2) (
[HOMECINEMA] => Array (
[id] => HOMECINEMA
[position] => 2
[title] => TV & Home Cinema
[children] => Array (
[HC-VISION] => Array (
[id] => HC-VISION
[title] => LCD & Plasma
[children] => Array (
[TVALL] => Array (
[id] => TVALL
[title] => All TVs
)
[LCD2] => Array (
[id] => LCD2
[title] => LCD/LED TVs
)
[PLASMA] => Array (
[id] => PLASMA
[title] => Plasma TVs
)
[3DTV] => Array (
[id] => 3DTV
[title] => 3D TV
)
[LED] => Array (
[id] => LED
[title] => SMART TVs
)
[PROJECTORS] => Array (
[id] => PROJECTORS
[title] => Projectors
)
[SYS-HOMECINEMATV] => Array (
[id] => SYS-HOMECINEMATV
[title] => TV Home Cinema Systems
)
)
)
[HC-SEPARATES] => Array (
[id] => HC-SEPARATES
[title] => Home Cinema Separates
[children] => Array (
[DVDRECORDERS] => Array (
[id] => DVDRECORDERS
[title] => DVD Recorders
)
[HDDVD] => Array (
[id] => HDDVD
[title] => Blu-ray
)
[AVRECEIVERS] => Array (
[id] => AVRECEIVERS
[title] => AV Receivers
)
[DVDPLAYERS] => Array (
[id] => DVDPLAYERS
[title] => DVD Players
)
[FREEVIEW] => Array (
[id] => FREEVIEW
[title] => Digital Set Top Boxes
)
[DVDPACKAGESYSTEMS-3] => Array (
[id] => DVDPACKAGESYSTEMS-3
[title] => 1 Box Home Cinema Systems
)
[HOMECINEMADEALS] => Array (
[id] => HOMECINEMADEALS
[title] => Home Cinema System Deals
)
)
)
[SPEAKER2] => Array (
[id] => SPEAKER2
[title] => Speakers
[children] => Array (
[SPEAKERPACKAGES] => Array (
[id] => SPEAKERPACKAGES
[title] => Speaker packages
)
[SOUNDBARS] => Array (
[id] => SOUNDBARS
[title] => Soundbars
)
[CENTRES] => Array (
[id] => CENTRES
[title] => Centres
)
[SUBWOOFERS] => Array (
[id] => SUBWOOFERS
[title] => Subwoofers
)
[FLOORSTANDING] => Array (
[id] => FLOORSTANDING
[title] => Floorstanders
)
[INSTALLATIONSPEAKERS] => Array (
[id] => INSTALLATIONSPEAKERS
[title] => Installation Speakers
)
[STAND-MOUNT] => Array (
[id] => STAND-MOUNT
[title] => Bookshelf Speakers
)
)
)
[HC-ACCYS] => Array (
[id] => HC-ACCYS
[title] => Accessories
[children] => Array (
[AVESSENTIALS] => Array (
[id] => AVESSENTIALS
[title] => AV Interconnects
)
[PLASMALCDSTANDSBRACKETS1] => Array (
[id] => PLASMALCDSTANDSBRACKETS1
[title] => TV Accessories
)
[RACKS] => Array (
[id] => RACKS
[title] => TV Racks
)
[HIFIRACKS] => Array (
[id] => HIFIRACKS
[title] => HiFi Racks
)
[PROJECTORACCYS] => Array (
[id] => PROJECTORACCYS
[title] => Projector Screens/Accessories
)
)
)
)
)
[SPEAKERS] => Array (
[id] => SPEAKERS
[position] => 3
[title] => Speakers
[children] => Array (
[SPK-HIFI] => Array (
[id] => SPK-HIFI
[title] => Hi-Fi
[children] => Array (
[STAND-MOUNT] => Array (
[id] => STAND-MOUNT
[title] => Bookshelf Speakers
)
[FLOORSTANDING] => Array (
[id] => FLOORSTANDING
[title] => Floorstanders
)
[INSTALLATIONSPEAKERS] => Array (
[id] => INSTALLATIONSPEAKERS
[title] => Installation Speakers
)
)
)
[SPK-HOMECINEMA] => Array (
[id] => SPK-HOMECINEMA
[title] => Home Cinema
[children] => Array (
[SPEAKERPACKAGES] => Array (
[id] => SPEAKERPACKAGES
[title] => Speaker Packages
)
[SOUNDBARS] => Array (
[id] => SOUNDBARS
[title] => Soundbars
)
[CENTRES] => Array (
[id] => CENTRES
[title] => Centres
)
[SUBWOOFERS] => Array (
[id] => SUBWOOFERS
[title] => Subwoofers
)
)
)
[SPK-ACCYS] => Array (
[id] => SPK-ACCYS
[title] => Accessories
[children] => Array (
[SPEAKERESSENTIALS1] => Array (
[id] => SPEAKERESSENTIALS
[title] => Speaker Cables
)
[SPEAKERSTANDS] => Array (
[id] => SPEAKERSTANDS
[title] => Speaker Stands
)
[SPEAKERBRACKETS] => Array (
[id] => SPEAKERBRACKETS
[title] => Speaker Wall Brackets
)
)
)
)
)
)
The example below will not necessarily be more performant (in time or memory requirements) but avoids manually recursing through the structure and shows an easier (IMHO) way to build your desired output array.
function search_in_array($needle, $haystack) {
$path = array();
$it = new RecursiveIteratorIterator(
new ParentIterator(new RecursiveArrayIterator($haystack)),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($it as $key => $value) {
if (array_key_exists('id', $value) && strcasecmp($value['id'], $needle) === 0) {
$path = array($needle);
for ($i = $it->getDepth() - 1; $i >= 0; $i--) {
$path = array($it->getSubIterator($i)->key() => $path);
}
break;
}
}
return $path;
}
Reference
RecursiveIteratorIterator::SELF_FIRST iteration mode - required to see non-"leaf" items
ParentIterator - easy way to filter out the "leaf" items
RecursiveIteratorIterator::getDepth()
RecursiveIteratorIterator::getSubIterator()
Bonus
You could also use the RecursiveIteratorIterator::setMaxDepth() method to limit the recursion to n levels deep, if your array also goes much deeper.