3

I have a question like this:

Create a function that takes in a nested array and an element and returns the frequency of that element by nested level.

Example:

freqCount([1, 4, 4, [1, 1, [1, 2, 1, 1]]], 1) ➞ [[0, 1], [1, 2], [2,3]] // The array has one 1 at level 0, 2 1's at level 1, and 3 1's at level 2.

So I have to use recursion since we don't know how many levels there are. I am getting the right number of occurrences of the $el passed but not the right level of depth because $depth keeps getting reset on every new call of recurse();

Here is the basic code:

<?php

function freqCount($arr, $el) {

recurse($arr, $el);

}

function recurse($a, $e) {

   $counter = 0;
     $depth = 0;
    $result = [];

    foreach($a as $k => $v) {
        if(!is_array($v) && $v === $e) {
            $counter++;
            $result[$depth] = $counter;
        } elseif(is_array($v)) {
            $depth++;
            recurse($v, $e);
        } else {
            continue;
        }
    }

    echo "<pre>";
    print_r($result);

}

Outputs:

Array
(
    [0] => 3 // Should be [2] => 3
)

Array
(
    [0] => 2 // Should be [1] => 2
)

Array
(
    [0] => 1
)
3
  • 1
    Probably want static $depth = 0; also I think you'll need to decrement it somewhere also. Commented Nov 2, 2020 at 21:30
  • @AbraCadaver: Nice static does keep track of the depth, thanks! Why would I need to decrement it? Here's the question: edabit.com/challenge/F96gXX2c8BvKnYiZ8 Commented Nov 2, 2020 at 21:31
  • It was just a quick look, you don't need to decrement it. Commented Nov 2, 2020 at 21:32

2 Answers 2

2

Your depth variable is locally scoped to the function and gets set to 0 each time the function is called. You need to pass the depth variable down the recursion so that it increments properly. Something like:

<?php

function freqCount($arr, $el) {
$depth = 0;
recurse($arr, $el, $depth);

}

function recurse($a, $e, $depth) {

    $counter = 0;
    $result = [];
    
    foreach($a as $k => $v) {
        if(!is_array($v) && $v === $e) {
            $counter++;
            $result[$depth] = $counter;
        } elseif(is_array($v)) {
            $depth++;
            recurse($v, $e, $depth);
        } else {
            continue;
        }
    }

    echo "<pre>";
    print_r($result);

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

Comments

1

Here's a possible simplified, PHP 7.4 version of what you're looking for:

function freqCount(array $values, $searchValue): array
{
    $frequencies = computeFrequencies($values, $searchValue, 0);

    return array_map(
        static fn (int $depth) => [$depth, $frequencies[$depth]],
        array_keys($frequencies)
    );
}

function computeFrequencies(array $values, $searchValue, int $depth): array
{
    $frequencies = [$depth => 0];

    foreach ($values as $value) {
        if ($value === $searchValue) {
            $frequencies[$depth]++;
        } elseif (is_array($value)) {
            foreach (computeFrequencies($value, $searchValue, $depth + 1) as $deeperDepth => $frequency) {
                $frequencies[$deeperDepth] = ($frequencies[$deeperDepth] ?? 0) + $frequency;
            }
        }
    }

    return $frequencies;
}

Usage:

print_r(freqCount([1, 4, 4, [1, 1, [1, 2, 1, 1]]], 1));  // [[0, 1], [1, 2], [2, 3]]
print_r(freqCount([1, [2], 1, [[2]], 1, [[[2]]], 1, [[[[2]]]]], 2));  // [[0, 0], [1, 1], [2, 1], [3, 1], [4, 1]]

It basically splits the task into two functions:

  • computeFrequencies is the "private" recursive one, it takes a $depth parameter and returns a level => occurrences associative array,
  • freqCount simply calls it once with $depth = 0, lets it do its thing then transforms the result into the desired output.

Demo (PHP 7.4)

Demo (PHP 7.2+)

10 Comments

Excellent, thank you my friend. This was considered an "expert" question (highest difficulty) and I felt confused. Would you say this is difficult based on (I assume) coding for a living? I'm trying to improve and was hoping I could've figured it out :(
@rec0nstr I didn't dig too deep into your code but it seems like you weren't that far off. Recursive functions are quite counter-intuitive when you're not used to them, so I wouldn't worry too much about it. It comes with habit.
Thank you! Very clean, modern solution :)
FYI: I receive error about :: when testing on the question site: "PHP Parse error: syntax error, unexpected 'fn' (T_STRING), expecting :: (T_PAAMAYIM_NEKUDOTAYIM)" -- I assume it's an earlier version of PHP?
Thanks, I believe it's 7.3 -- So I think the arrow function is problematic.
|

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.