2

Really struggling with this. I have a multidimensional array n levels deep. Each 'array level' has information I need to check (category) and also check if it contains any arrays.

I want to return the category ids of all the arrays which have a category and do not contain an array (i.e. the leaves). I can echo output properly, but I am at a loss as how to return the ids in an array (without referencing)

I have tried RecursiveIteratorIterator::LEAVES_ONLY and RecursiveArrayIterator but I don't think they work in my case? (Maybe I am overlooking something)

$array

array(2) {
  ["1"]=>
  string(5) "stuff"
  ["2"]=>
  array(2) {
    ["category"]=>
    string(1) "0"
    ["1"]=>
    array(3) {
      [0]=>
      array(3) {
        ["category"]=>
        string(1) "1"
        ["1"]=>
        string(5) "stuff"
        ["2"]=>
        string(5) "stuff"
      }
      [1]=>
      array(5) {
        ["category"]=>
        string(1) "2"
        ["1"]=>
        string(5) "stuff"
        ["2"]=>
        string(5) "stuff" 
      }
      [1]=>
      array(5) {
        ["1"]=>
        string(5) "stuff"
        ["32"]=>
        string(5) "stuff" 
      }
    }
  }
}

My function

public function recurs($array, $cats = [])
{
    $array_cat = '';
    $has_array = false;

    // Check if an id exists in the array
    if (array_key_exists('category', $array)) {
        $array_cat = $array['category'];
    }

    // Check if an array exists within the array
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $has_array = true;
            $this->recurs($value, $cats);
        }
    }

    // If a leaf array
    if (!$has_array && is_numeric($array_cat)) {
        echo "echoing the category here works fine: " . $array_cat . "\n";

        return $array_cat;
    }
}

Calling it

$cats_array = $this->recurse($array)

Output echoed

echoing the category here works fine: 1
echoing the category here works fine: 2

How do I return the ids in an array to use in the $cats_array variable?

EDIT: The output should match the echo, so I should get an array containing (1, 2) since they are the only arrays with categories and no arrays within them

array(2){
    [0]=>
    int(1) "1"
    [1]=>
    int(1) "2"
}
1
  • 1
    Can you give an example of what you're expecting as the result? Commented Dec 10, 2015 at 14:26

1 Answer 1

3

If I understood you correctly this function will do the job:

function getCategories(array $data)
{
    if ($subArrays = array_filter($data, 'is_array')) {
        return array_reduce(array_map('getCategories', $subArrays), 'array_merge', array());
    };

    return array_key_exists('category', $data) ? array($data['category']) : array();
}

If the array contains any sub-arrays they will be returned by array_filter and you will enter the if statement. array_map will apply the function recursively to the sub-arrays and array_reduce will merge the results.

If the array doesn't contain any sub-arrays you will not enter the if statement and the function will return an array with the category if it is present.

Note that you might need to use array_unique to return unique categories.

Also for small performance optimization instead of array_key_exists you can use isset($array[$key]) || array_key_exists($key, $array).

Update

If you want to update your function to make it work you have to recursively collect and merge the sub results. In the following example I introduced a new variable for this:

public function recurs($array, $cats = [])
{
    $result = [];

    $array_cat = '';
    $has_array = false;

    // Check if an id exists in the array
    if (array_key_exists('category', $array)) {
        $array_cat = $array['category'];
    }

    // Check if an array exists within the array
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $has_array = true;
            $result = array_merge($result, $this->recurs($value, $cats));
        }
    }

    // If a leaf array
    if (!$has_array && is_numeric($array_cat)) {
        echo "echoing the category here works fine: " . $array_cat . "\n";

        return [$array_cat];
    }

    return $result;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, this does indeed work and is nice and compact. I was hoping however someone could expand on my attempt so I can understand what I was doing wrong.
Do you happen to know of any good on-line material explaining recursion in PHP in detail? I can only find factorial examples.
Unfortunately, no. Recursion in PHP is the same as in many other languages. Just search for recursion and you might find something you like with examples in another programming language.

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.