0

If I have an array that could be infinitely deep, how can I refer to a specific value if I have an array of keys.

Example array:

Array
(
    [a] => Array
        (
            [id] => something
            ...
        )

    [b] => Array
        (
            [id] => something
            ...
        )
)

In the above example array, what would I do if I instead had a function like this:

function example($keys)
{
    $keys = array("a", "id"); // example keys
    $this->data[...$keys] = "something";
    // $this->data["a"]["id] = "something";
}

Please note that I can't just run a loop to get the value because I need to refer to the original array, not create a new one. So something like this is not what I need

$data = $this->data;
foreach($keys as $v){
    $data = $data[$v];
}

What I really need is just a simple way to refenence the original using the keys array.

1
  • Do you have two arrays? I don’t quite understand. Commented Nov 15, 2021 at 1:50

1 Answer 1

1

So you want to look for a value on an array where you know the path to?
Had the same thing, build me something.

Its not perfect. But it does the job.
Note: if you change it then do not return false if path not found. Because false could be a found value too.

The method:

/**
 * Returns a value from given source by following the given keys.
 *
 * Example:
 * <code>
 * $array = [
 *     'foo' => [
 *         'bar'   => [
 *             'baz' => null,
 *         ],
 *         'bar_2' => [
 *             0 => [
 *                 'baz' => null,
 *             ],
 *             1 => [
 *                 'baz' => 123,
 *             ],
 *             2 => [
 *                 'baz' => 456,
 *             ],
 *         ]
 *     ]
 * ];
 * ::find($array, ['foo', 'bar_2', 1, 'baz']) // 123
 * </code>
 *
 * @param array $source
 * @param array $keys
 *
 * @return array|bool|mixed
 */
public function find(array $source, array $keys)
{
    if (empty($keys)) {
        // No keys - so actually expect the complete source to return.
        return $source;
    }
    // Get the (next-) first key.
    $keyCurrent = array_shift($keys);
    if (!array_key_exists($keyCurrent, $source)) {
        // Expected path to value does not exist.
        throw new \InvalidArgumentException("Key '{$keyCurrent}' not found.");
    }
    $source = $source[$keyCurrent];
    if (!empty($keys)) {
        // Still got keys - need to keep looking for the value ...
        if (!is_array($source)) {
            // but no more array - cannot continue.
            // Expected path to value does not exist. Return false.
            throw new \InvalidArgumentException("No array on key '{$keyCurrent}'.");
        }
        // continue the search recursively.
        $source = $this->find($source, $keys);
    }
    // No more keys to search for.
    // We found the value on the given path.
    return $source;
}

The test:

$array = [
    'a' => ['id' => 'something at array[a][id]'],
    'b' => ['id' => 'something at array[b][id]'],
    'c' => [
        'ca' => [
            'cb' => [
                'cc' => ['id' => 'something at array[c][ca][cb][cc][id]'],
            ],
        ],
    ],
];

$value = $this->find($array, ['c', 'ca', 'cb', 'cc', 'id']);
// something at array[c][ca][cb][cc][id]

$value = $this->find($array, ['c', 'ca', 'cb', 'cc']);
// array (
//     'id' => 'something at array[c][ca][cb][cc][id]',
// )

$value = $this->find($array, ['b', 'id']);
// something at array[b][id]

$value = $this->find($array, ['c', 'ca', 'cb', 'cc', 'does_not_exist']);
// Fatal error: Uncaught InvalidArgumentException: Key 'does_not_exist' not found. in
Sign up to request clarification or add additional context in comments.

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.