3

Let’s say I have two arrays, one is of keys I require, the other is an array I want to test against.

In the array of keys I require, each key might have a value which is itself an array of keys I require, and so on.

Here’s the function so far:

static function keys_exist_in_array(Array $required_keys, Array $values_array, &$error)
{       
    foreach($required_keys as $key)
    {
        //  Check required key is set in the values array
        //          
        if (! isset($values_array[$key]))
        {
            //  Required key is not set in the values array, set error and return
            //
            $error = new Error();

            return false;
        }

        //  Check the value is an array and perform function on its elements
        //
        if (is_array($values_array[$key]))
        {
            Static::keys_exist_in_array($required_keys[$key], $values_array[$key], $error);
        }

        return true;
    }
}

My problem is that the array I want to submit to $required_keys CAN look like this:

$required_keys = array(
    ‘key1’,
    ‘key2’,
    ‘key3’,
    ‘key4’ = array(
        ‘key1’,
        ‘key2’,
        ‘key3’ = array(
            ‘key1’
        )
    )
);

Obviously the problem here is that foreach only finds each key, e.g. ‘key4’, rather than the values without their own value, e.g. ‘key1’, ‘key2’, ‘key3’.

But if I loop through with a standard for loop, I only get the values, key1, key2, key3.

What’s a better way of doing this?

Thanks

6
  • 1
    When looping check if the value is an array and if so call the function again inside the loop and pass the value (array). Commented Feb 6, 2015 at 0:30
  • check the type of element, if it's an array, recurse on that element! Commented Feb 6, 2015 at 0:30
  • stackoverflow.com/questions/2648968/… Commented Feb 6, 2015 at 0:31
  • As stated above, the problem is with the looping. Foreach only gives keys, for only gives values. I need both in one loop… Lines 18-21 are the recursive function Commented Feb 6, 2015 at 0:31
  • Why do you need both? key1, key2, etc. are all values. Your array is strange: why is it a mix of an indexed and associative arrays? Commented Feb 6, 2015 at 0:40

3 Answers 3

2

Several problems:

$key is the element of the array, not a key, so you

You shouldn't return false as soon as you see a non-matching element, because there could be a matching element later in the array. Instead, you should return true as soon as you find a match. Once you find a match, you don't need to keep searching.

You need to do the isarray() test first, because you'll get an error if $key is an array and you try to use $values_array[$key]. And it should be isarray($key), not isarray($values_array[$key]).

You need to test the value of the recursive call. If it succeeded, you can return immediately.

You should only return false after you finish the loop and don't find anything.

static function keys_exist_in_array(Array $required_keys, Array $values_array, &$error)
{       
    foreach($required_keys as $key)
    {
        //  Check the value is an array and perform function on its elements
        //
        if (is_array($key))
        {
            $result = Static::keys_exist_in_array($required_keys[$key], $values_array[$key], $error);
            if ($result) {
                return true;
            }
        }            
        //  Check required key is set in the values array
        //          
        elseif (isset($values_array[$key]))
        {
            return true;
        }
    }
    $error = new Error();
    return false;
}
Sign up to request clarification or add additional context in comments.

Comments

1

Convert the array to a key => value array with an empty value for the "keys" that don't have a value.

$arr = [
    'a',
    'b' => ['foo' => 1, 'bar' => 'X'],
    'c' => ['baz' => 'Z'],
    'd'
];

$res = [];
$keys = array_keys($arr);
$vals = array_values($arr);
foreach ($vals as $i => $v) {
    if (is_array($v)) {
        $res[$keys[$i]] = $v;
    } else {
        $res[$v] = [];
    }
}

print_r($res);

Result:

Array
(
    [a] => Array
        (
        )

    [b] => Array
        (
            [foo] => 1
            [bar] => X
        )

    [c] => Array
        (
            [baz] => Z
        )

    [d] => Array
        (
        )
)

Comments

0

Returning false here is the correct action if you require that ALL the $required_keys exist, because you want it to stop looking as soon as it finds a missing key.

static function keys_exist_in_array(Array $required_keys, Array $values_array, &$error)
{       
    foreach($required_keys as $key=>$value)
    {
        //check if this value is an array
        if (is_array($value))
        {
            if (!array_key_exists($key, $values_array) 
                || !Static::keys_exist_in_array($value, $values_array[$key], $error);){
                $error = new Error();
                return false;
            }


        }

        //  Since this value is not an array, it actually represents a 
        //   key we need in the values array, so check if it is set 
        //   in the values array    
        elseif (!array_key_exists($value, $values_array))
        {
            //  Required key is not set in the values array, set error and return
            $error = new Error();
            return false;
        }


    }
    //All elements have been found, return true
    return true;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.