-1

I have a multidimensional array as per below example which I want to search through for a specific value $needle. If this value is found I want to add a new key=> value pair for each node of the array branch where the $needle is subsequently found. The needle should be unique but the depth of the sub arrays is dynamic. Example:

$data= [
    0=> [
        'title'     => 'alpha',
        'children'  => [],
        ],
    1 =>[
        'title'     => 'beta',
        'children'  => [
         0=>[
             'title'     => 'charlie',
             'children'  => [],
            ],
         1=>[
             'title'     => 'delta',
             'children'  => [],
            ],
         2=>[
             'title'     => 'echo',
             'children'  => [
            0=>[
               'title'     => 'foxtrot',
               'children'  => [],
                    ],                      
                ],
            ],              
        ],
        ],      
  2 =>  [
        'title'     => 'gulf',
        'children'  => []
  ]

Now when I search for $needle= foxtrot I want to add to each of the subarrays "active" => 1 e.:

   $data= [
    0=> ...
    1 =>[
        'title'     => 'beta',
        **'active' => 1,**
        'children'  => [
         0=>[
             'title'     => 'charlie',
             'children'  => [],
            ],
         1=>[
             'title'     => 'delta',
             'children'  => [],
            ],
         2=>[
             'title'     => 'echo',
             **'active' => 1,**
             'children'  => [
            0=>[
               'title'     => 'foxtrot',
               **'active' => 1,**
               'children'  => [],
                    ],                      
                ],
            ],              
        ],
        ], 

My not working attempt. I don't know how I correctly merge the key => value on each finding:

function array_mod_active($array, $needle, $parent_key='' )
{
foreach($array as $key => $value) {
    if (is_array($value)) {
        array_mod_active($value, $needle, $key );

    } elseif ($value === $needle) {
        array_merge(array('active' => 1), $array[$parent_key]);

    }
}

return $array;
}
Eike
  • 451
  • 1
  • 4
  • 17
  • Take a look at [this question](https://stackoverflow.com/q/42330991/1685196), or [this one](https://stackoverflow.com/q/8440352/1685196), or [this one](https://stackoverflow.com/q/38720862/1685196) or... – Michel Jan 31 '18 at 12:54
  • @RiggsFolly - You are right - my intentions was not to get the code written but I felt that I taking the wrong approach with my foreach loops thus I wanted more of a direction. – Eike Jan 31 '18 at 13:49
  • You had not show your coding attempt when I made that comment, and did not add them until roughly 1 hour after you asked the question. For future reference give us all the information at the start, and hang around for 10 minutes at least after posting to answer any questions people may have – RiggsFolly Jan 31 '18 at 15:22

1 Answers1

1

This is one recursive way to do it. I've added inline comments to explain each step.

Code: (Demo)

function keysort($a,$b){  // this function is optional; purely used for aesthetic/readability purposes
    $order=['title'=>0,'active'=>1,'children'=>2];  // order keys by this specific order
    return $order[$a]<=>$order[$b];
}
function activate_lineage(&$array,$needle){
    foreach($array as &$item){
        if($item['title']==$needle){  // $needle located, make active
            $item['active']=1;  // add active element
            uksort($item,'keysort');  // optional call
            return $array;  // send full updated array back where it came from
        }elseif(!empty($item['children'])){  // drill down if there are any children
            $copy=$item;  // preserve original (this avoids a post-recursion column-search)
            $item['children']=activate_lineage($item['children'],$needle);  // recurse
            if($copy!==$item){  // if children subarray was updated, a child was activated
                $item['active']=1;  // add active element
                uksort($item,'keysort');  // optional call
                break;  // don't continue the loop; only one parent will be activated (per level)
            }
        }
    }
    return $array;  // return the full array, no matter what level it is on
}

// to call:
var_export(activate_lineage($data,'foxtrot'));

/* or because the function modifies by reference...

    activate_lineage($data,'foxtrot');
    var_export($data);

*/
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • 1
    This is a great and compact solution - that makes all my different failed attempts look so overcomplicated. I appreciate the detailed comments which helped me to understand the code - especially usage of the little "&". – Eike Feb 02 '18 at 13:23