5

I have this haystack array:

$array = [
   [
      "name" => "Intro",
      "id" => "123",
      "children" => [
         "name" => "foo",
         "id" => "234",
         "children" => [
            "name" => "mur",
            "id" => "445",
         ]
      ]
   ],[
      "name" => "chapter one",
      "id" => "9876",
      "children" => [
         "name" => "foo",
         "id" => "712",
         "children" => [
            "name" => "bar",
            "id" => "888",
         ]
      ]
   ]
];

And this needle array: $needle = ["chapter one","foo","bar"]

I'm working on a recursive search function that will return the id value of the child element matching on column name following the path of $needle.

In the example, it should return 888. I have this so far but I don't find how to follow the $needle path as opposed to finding values assuming they're unique. Appreciate any help putting me on the right track.

function searchTree( $needle, $haystack, $strict=false, $path=array() )
{
   if( !is_array($haystack) ) {
      return false;
   }

   foreach( $haystack as $key => $val ) {
   if( is_array($val) && $subPath = searchTree($needle, $val, $strict, $path) ) {
      $path = array_merge($path, array($key), $subPath);
      return $path;
   } elseif( (!$strict && $val == $needle) || ($strict && $val === $needle) ) {
      $path[] = $key;
      return $path;
   }
    }
    return false;
}
2
  • I assume since it's recursive, that $needle can hold infinite values or will it always be 3? Commented Jul 28, 2015 at 23:31
  • @Darren infinite values indeed. And items at same level of an array have unique names. Commented Jul 28, 2015 at 23:32

1 Answer 1

4

I'll try to clean it up a bit, but this works:

$needle = ["chapter one", 'foo', 'bar'];
$array = [
    [
        "name" => "Intro",
        "id" => "123",
        "children" => [
            "name" => "foo",
            "id" => "234",
            "children" => [
                "name" => "mur",
                "id" => "445",
            ]
        ]
    ],[
        "name" => "chapter one",
        "id" => "9876",
        "children" => [
            "name" => "foo",
            "id" => "712",
            "children" => [
                "name" => "bar",
                "id" => "888",
            ]
        ]
    ]
];

function searchTree($needle, $haystack, $strict=false) {
    if(!is_array($haystack)) {
        return false;
    }
    $match = false;
    if(array_keys($haystack) !== range(0, count($haystack) - 1) && !empty($needle)) {
        if(($strict && $haystack['name'] === $needle[0]) || (!$strict && $haystack['name'] == $needle[0])) {
            $match = true;
            array_shift($needle);
            if (!empty($needle)) {
                return searchTree($needle, $haystack['children'], $strict);
            }
        }
    } else {
        foreach ($haystack as $key => $value) {
            if (is_array($value) && !empty($needle)) {
                if (($strict && $value['name'] === $needle[0]) || (!$strict && $value['name'] == $needle[0])) {
                    $match = true;
                    array_shift($needle);
                    if (!empty($needle)) {
                        return searchTree($needle, $value['children'], $strict);
                    } else {
                        $haystack = $haystack[$key];
                    }
                }
            }
        }
    }
    return (isset($haystack['id']) && $match) ? $haystack['id'] : false;
}

echo searchTree($needle, $array);

output:

888
Sign up to request clarification or add additional context in comments.

6 Comments

Oh that's awesome. It's working except for when there's only one value in $needle.
Working on it. Needs an adjustment still, I noticed.
Np. Thanks for the question. It was a fun one.
Hmm, think there's a problem if you try $needle = ["Intro"]: Undefined offset: 0. Might need something like if (is_array($value) && !$match)
It's fixed again haha.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.