Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP recursive function bug?

I made this function to search inside nested array but I keep getting null for this array:

$arr3 = [
    'first' => 1,
    'second' => 2,
    'third' => [
        'fourth' => 4,
    ]
];

/**
 * returns the key for the first found value
 *
 * @param $needle
 * @param array $haystack
 * @return false|int|string
 */
function array_search_value($needle, array $haystack) {

    $result = null;
    $found = array_search($needle, $haystack);

    if ( $found !== false ) {
        // end the recursion
        $result = $found;

    } else {
        foreach ($haystack as $key => $item) {
            if (is_array($item)) {
                array_search_value($needle, $item);
            } else {
                continue;
            }
        }
    }

    return $result;
}

var_dump(array_search_value(4, $arr3));

I can't figure it out what have I done wrong? The var_dump() result should be string "fourth".

like image 291
lewis4u Avatar asked Mar 04 '23 13:03

lewis4u


2 Answers

If you find the thing you're looking for during recursion you're not really storing it anywhere. Here's my recommended approach:

$arr3 = [
    'first' => 1,
    'second' => 2,
    'third' => [
        'fourth' => 4,
    ]
];

/**
 * returns the key for the first found value
 *
 * @param $needle
 * @param array $haystack
 * @return null|array
 */
function array_search_value($needle, array $haystack) {

    $result = null;
    $found = array_search($needle, $haystack);

    if ( $found !== false ) {
        // end the recursion
        $result = [ $found ]; //Array will make sense in a bit

    } else {
        foreach ($haystack as $key => $item) {
            if (is_array($item)) {
                $found = array_search_value($needle, $item);
                if ($found !== null) {
                   return array_merge([$key],$found);
                }
            } else {
                continue;
            }
        }
    }

    return $result;
}

var_dump(array_search_value(4, $arr3));

The reason for returning an array is in case the subarray has the same key as the main array so you would be able to consistently retrieve the correct key by recursively accesssing the array index for each array entry returned.

Check out the code at: http://sandbox.onlinephpfunctions.com/code/085c949f660504010ed7ebb7a846e31b3a766d61

Here's an example as to why the returning of an array may be necessary:

If you consider the array:

$arr3 = [
    'a' => 1,
    'b' => 2,
    'c' => [
        'a' => 4,
    ],
    "d"=>[
        "a" => [
            "a" => 19    
        ]
    ]
];

If you're looking for 4 and not return an array you'll get back a but that will also be ambiguous because a contains 1 in the root array

http://sandbox.onlinephpfunctions.com/code/43c2f2dfa197400df1e5748e12f12e5346abed3e

You could modify the above to get all paths that lead to the given result if there are more than one.

function array_search_value_all($needle, array $haystack) {

    $result = [];
    $found = array_search($needle, $haystack);

    if ( $found !== false ) {
        // end the recursion
        $result[] = [ $found ]; //Array will make sense in a bit

    } else {
        foreach ($haystack as $key => $item) {
            if (is_array($item)) {
                $found = array_search_value($needle, $item);
                if ($found !== []) {
                   $result[] = array_merge([$key],$found);
                }
            } else {
                continue;
            }
        }
    }

    return $result;
}

array_search_value_all will return an array of all paths leading to that value.

Example: http://sandbox.onlinephpfunctions.com/code/fa4f5274703abb221f171c6e3ace5529594cdc8c

like image 166
apokryfos Avatar answered Mar 17 '23 04:03

apokryfos


You are missing assign of the recursive call to you $result. You need to change:

if (is_array($item)) {
     array_search_value($needle, $item);

To: (notice that is the value not found keep searching and not just return)

if (is_array($item) ) {
    $i = array_search_value($needle, $item);
    if ($i)
        return $i;
like image 36
dWinder Avatar answered Mar 17 '23 06:03

dWinder