【问题标题】:get all array keys by value按值获取所有数组键
【发布时间】:2013-01-31 21:06:48
【问题描述】:

假设我有一个这样的数组:

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
    )

)

是否有一个 php 函数可用于获取指向数组中值 x 的路径,这意味着,在这种情况下,结果将是:

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

【问题讨论】:

  • 你可以试试serialize()
  • 查看图搜索算法,如 BFS 和 DFS。
  • 我觉得这个问题每天都在重复...stackoverflow.com/questions/7817727/…
  • @Akam 答案没有显示如何获取密钥路径Start, Item 1, Item 2_1, Item 2_1_1
  • 我想看看array_walk_recursive,或者如果你对SPL 的RecursiveIteratorIterator 有什么感觉。据我所知,没有原生 PHP 函数可以做到这一点。

标签: php arrays multidimensional-array


【解决方案1】:

我目前能想到的唯一方法是大量嵌套foreach ($array as $key => $value) 循环和array_search()

虽然将其设为递归会更好,因此使用函数是明智的。

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);
            }
        }
    }
}

只是一个尝试,不一定有效或类似的东西。

【讨论】:

    【解决方案2】:

    您遇到的问题涉及递归和/或树遍历。 PHP 支持使用RecursiveArrayIteratorRecursiveIteratorIterator 对数组进行树遍历。

    要获取所有父数组的所有key,需要从第一层到当前深度获取key。 RecursiveIteratorIterator 也支持 getSubIterator() 方法。手册中并没有很好地记录,所以这里是一个例子:

    $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";
    }
    

    在本例中,首先创建带有$arrayRecursiveArrayIterator。为了启用树遍历,它被包装到RecursiveIteratorIterator 中。这是以递归方式使用 $it-iterator 和 foreach 所必需的。

    然后,在foreach 中,将根据您的搜索值检查数组值。如果不匹配,则继续下一个值。

    但如果它确实匹配递归迭代器上的getDepth()getSubIterator() 方法,则用于创建键数组。

    该示例执行以下输出:

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

    与您在问题中的描述相符。

    因为这些是迭代器,您也可以将其实现到它自己的类中。以下Iterator 类不仅允许对构造函数中提供的数组进行树遍历,而且还有一个名为getKeys() 的方法,它返回一个包含从最低级别到当前深度的所有键的数组:

    /**
     * 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;
        }
    }
    

    然后它更易于使用(并且可能也适用于其他场景)。所以首先是一些基本的用法示例。遍历数组显示每个值的所有键。为您的数组实例化迭代器并输出每个值的键:

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

    这将创建以下输出:

    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
    

    在您的场景中,您还希望根据特定值(此处为字符串"x")过滤迭代器,您可以通过使用RegexIterator(即FilterIterator)轻松完成此操作。这就是你的场景:

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

    这里是输出:

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

    如您所见,它会针对您感兴趣的值进行过滤。

    您可能感兴趣的其他相关问题是:

    【讨论】:

    • 谢谢。你想压平什么?每个迭代它已经是线性顺序的,并且键只需要特定值,所以不需要展平整个数组。
    猜你喜欢
    • 1970-01-01
    • 2016-12-15
    • 2014-10-03
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    相关资源
    最近更新 更多