Get all keys of an array by value

Let's say I have an array like this:

Array
(
[Start] => Array
    (
        [Item 1] => Array
            (
                [0] => Item 1_1
                [Item 2_1] => Array
                    (
                        [Item 2_1_1] => x
                    )

                [1] => Item 3_1
            )

        [0] => Item 2
        [1] => Item 3
    )

      

)

Is there a php function I can use to get the path that leads to the value x

in my array, i.e. in this case, the result would be:

Start, Item 1, Item 2_1, Item 2_1_1, x

      

+3


source to share


2 answers


The only method I can think of right now is having many nested loops foreach ($array as $key => $value)

along with array_search()

.

It would be better if the design was recursive, so using a function would make sense.



function recursiveSearch($key, $array)
{
    foreach ($array as $k => $ar) {
        if (is_array('x', $ar)) {
            return $k . ', ' . array_search('x', $ar);
        } else {
            if ($ar === 'x') {
                return $k
            } else {
                return recursiveSearch($key, $ar);
            }
        }
    }
}

      

Just take it, not necessarily working or something.

+2


source


The problem you are having involves recursion and / or tree traversal. PHP supports traversing an array tree using RecursiveArrayIterator

and RecursiveIteratorIterator

.

To get all the keys of all parent arrays, you need to get from the first level to the current depth and get the keys. This is supported RecursiveIteratorIterator

as well with the method getSubIterator()

. It's not well documented in the manual, so here's one example:

$it = new RecursiveIteratorIterator(
    new RecursiveArrayIterator($array)
);

foreach ($it as $value) {
    if ($value !== 'x') continue;

    $keys  = array();
    $depth = $it->getDepth();
    for ($i = 0; $keys[] = $it->getSubIterator($i)->key(), $depth--; $i++);

    echo implode(', ', $keys), ', ', $value, "\n";
}

      

This example is created primarily RecursiveArrayIterator

with yours $array

. To enable tree traversal, it is wrapped in RecursiveIteratorIterator

. This is required for recursive use of the $it

-terator with foreach

.

Internally foreach

then the array value is checked against your lookup value. If it doesn't match, it continues with the next value.

But if it matches methods getDepth()

and getSubIterator()

on a recursive iterator, then it is used to create an array of keys.

The example shows the following output:

 Start, Item 1, Item 2_1, Item 2_1_1, x

      

Which matches your description in the question.

Since they are iterators, you can implement this in your class as well. The following class Iterator

allows not only to traverse the tree through the array represented in the constructor, but also to have a named method getKeys()

that returns an array containing all keys from the lowest level to the current depth:

/**
 * Class ArrayRecursiveKeysIterator
 */
class ArrayRecursiveKeysIterator extends RecursiveIteratorIterator
{
    /**
     * @param array $array
     */
    public function __construct(array $array)
    {
        parent::__construct(new RecursiveArrayIterator($array));
    }

    /**
     * @return array keys
     */
    public function getKeys()
    {
        for ($k = [], $i = 0, $m = $this->getDepth(); $i <= $m; $i++)
            $k[] = $this->getSubIterator($i)->key();
        return $k;
    }
}

      



Then it's easier to use (and probably also for other scenarios). So let's first look at an example of use. Step through the array, show all the keys for each value. Initialize an iterator for your array and output the keys per value:

$it = new ArrayRecursiveKeysIterator($array);
foreach ($it as $value) {
    echo implode(', ', $it->getKeys()), ', ', $value, "\n";
}

      

This creates the following output:

Start, Item 1, 0, Item 1_1
Start, Item 1, Item 2_1, Item 2_1_1, x
Start, Item 1, 1, Item 3_1
Start, 0, Item 2
Start, 1, Item 3

      

In your scenario, you also want to filter the iterator based on a specific value (here's a string "x"

), which you can easily do using RegexIterator

which is FilterIterator

. Then this is your scenario:

$it     = new ArrayRecursiveKeysIterator($array);
$filter = new RegexIterator($it, '~^x$~');
foreach ($filter as $value) {
    echo implode(', ', $it->getKeys()), ', ', $value, "\n";
}

      

And here's the output:

Start, Item 1, Item 2_1, Item 2_1_1, x

      

As you can see, it is filtered for the value you are interested in.

Other questions that interest you:

+1


source







All Articles