Search code examples
phparray-walk

How do I get the value of the first occurrence of array_walk_recursive in php


I have a deep multidimensional array that I am needing to extract the value of a specific key. I have found that the array_walk_recursive function will be my best option. I only need the first occurrence.

My array looks like this - (except much more complicated)

Array (
    [vehicle info] => Array (
        [one] => Array (
            [submodel] => LX
            [engine] => 2.3
        )
        [two] => Array (
            [color] => blue
            [year] => 2007
            [wheels] => 4
        )
        [three] => Array (
            [submodel] => LX
            [make] => Ford
            [model] => F-150
            [offroad] => No
        )
    )
)

The issue here is, submodel is in both one and three. Additionally, the array is not consistent, so I must use array_walk_recursive to search through it for the matching key, then return the value for that key.

Here is my current code -

array_walk_recursive ($array, (function ($item, $key) {
    $wanted = "submodel";
    if ($key === $wanted) {
        echo ("$key is $item");
    }
}));

The above returns submodel is LXsubmodel is LX.

Bonus Question!! How can I search for multiple keys and return the first corresponding value for each of those? I was thinking putting all wanted keys in an array, then do a foreach loop, but don't quite know how to structure this. I am new to php.


Solution

  • array_walk_recursive() is the appropriate native function to call for this task. Keep track of which keys have already been declared in the result array and ensure that they are never overwritten.

    Code: (Demo)

    $needles = ['submodel', 'offroad'];
    $result = [];
    array_walk_recursive(
        $array,
        function($value, $key) use ($needles, &$result) {
            if (
                in_array($key, $needles)
                && !key_exists($key, $result)
            ) {
                $result[$key] = "$key is $value";
            }
        }
    );
    var_export($result);
    

    Output:

    array (
      'submodel' => 'submodel is LX',
      'offroad' => 'offroad is No',
    )
    

    For improved performance when you only want the first qualifying match, write return; as the last line inside of the if block.


    Alternatively, you can design your own recursive function which will return when all sought keys are found.

    Code: (Demo)

    $soughtKeys = array_flip(['submodel', 'offroad']);
    
    function earlyReturningRecursion(array $array, array $soughtKeys, array &$result = []): array
    {
        foreach ($array as $key => $value) {
            if (!array_diff_key($soughtKeys, $result)) {  // check if result is complete
                return $result;
            } elseif (is_array($value)) {
                earlyReturningRecursion($value, $soughtKeys, $result);
            } elseif (isset($soughtKeys[$key]) && !key_exists($key, $result)) {
                $result[$key] = "$key is $value";
            }
        }
        return $result;
    }
    var_export(earlyReturningRecursion($array, $soughtKeys));
    // same output as the first snippet