Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP - Looping through a mixed array

Tags:

arrays

php

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

like image 598
Adam Carter Avatar asked Feb 12 '26 04:02

Adam Carter


2 Answers

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;
}
like image 173
Barmar Avatar answered Feb 13 '26 17:02

Barmar


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
        (
        )
)
like image 41
gregjor Avatar answered Feb 13 '26 17:02

gregjor