phparraysrecursionmultidimensional-arrayhierarchical-data

Recursively search a hierarchical multidimensional array for partial value matches in a column and return values in another column found on the way


I have a hierarchical array in my project like this:

$Array = array(
    array(
        'Id' => 1,
        'Title' => 'Some Text1',
        'Children' => array(
            array(
                'Id' => 11,
                'Title' => 'Some Text11',
                'Children' => array(
                    array(
                        'Id' => 111,
                        'Title' => 'Some Text111',
                    ),
                    array(
                        'Id' => 112,
                        'Title' => 'Some Text112',
                        'Children' => array(
                            array(
                                'Id' => 1121,
                                'Title' => 'Some Text1121',
                            )
                        )
                    )
                )
            ),
            array(
                'Id' => 12,
                'Title' => 'Some Text12',
                'Children' => array(
                    array(
                        'Id' => 121,
                        'Title' => 'Some Text121',
                    )
                )
            )
        )
    ),
    array(
        'Id' => 2,
        'Title' => 'Some Text2',
    )
);

I want to search Title columns with a passed in string (such as Some Text1121) and return its path composed of Id values.

If the search is for Some Text1121, I want to return:

1 -> 11 -> 112 -> 1121

Or when I Search 'Some' string, return all Id paths in array.


Solution

  • I've quickly written you something. It's not perfect, but you get the idea:

    <?php
    
    function searchRec($haystack, $needle, $pathId = Array(), $pathIndex = Array()) {
        foreach($haystack as $index => $item) {
            // add the current path to pathId-array
            $pathId[] = $item['Id'];
            // add the current index to pathIndex-array
            $pathIndex[] = $index;
            // check if we have a match
            if($item['Title'] == $needle) {
                // return the match
                $returnObject = new stdClass();
                // the current item where we have the match
                $returnObject->match = $item;   
                // path of Id's (1, 11, 112, 1121)
                $returnObject->pathId = $pathId; 
                // path of indexes (0,0,1,..) - you might need this to access the item directly
                $returnObject->pathIndex = $pathIndex; 
                return $returnObject;
            }
    
            if(isset($item['Children']) && count($item['Children']>0)) {
                // if this item has children, we call the same function (recursively) 
                // again to search inside those children:
                $result = searchRec($item['Children'], $needle, $pathId, $pathIndex);
                if($result) {
                    // if that search was successful, return the match-object
                    return $result;
                }
            }
        }
        return false;
    }
    
    // useage:
    $result = searchRec($Array, "Some Text11");
    var_dump($result);
    
    // use 
    echo implode(" -> ", $result->pathId);
    // to get your desired 1 -> 11 -> 112
    

    EDIT: rewritten to make the function actually return something. It now returns an Object with the matching item, the path of Id's and the path of (array-) Indexes.