通过值获取所有数组键

4

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

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() - fedorqui
请查看图形搜索算法,例如BFS和DFS。 - Brad Bonkoski
我认为这个问题每天都在重复... http://stackoverflow.com/questions/7817727/search-a-multidimensional-array-php - user1646111
@Akam,这个答案没有展示如何获取键路径“Start,Item 1,Item 2_1,Item 2_1_1”。 - Baba
我建议您查看array_walk_recursive,或者如果您感觉高级一些,可以使用SPL的RecursiveIteratorIterator。据我所知,PHP没有本地函数可以完成这个任务。 - ficuscr
如果找到该代码的值,您无法返回该代码的密钥吗? - user1646111
2个回答

2

目前我能想到的唯一方法是使用大量嵌套的 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遍历数组的树形结构。
要获取所有父级数组的所有键,您需要从第一层向上到当前深度并获取键。这也可以通过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";
}

在这个例子中,首先创建一个带有你的 $array 的 RecursiveArrayIterator。为了启用树遍历,它被包装成 RecursiveIteratorIterator。这是必要的,以便在递归方式下使用 $it 迭代器和 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

如您所见,它已经为您感兴趣的值进行了过滤。

其他相关问题可能会引起您的兴趣:


谢谢。你想要展开什么?根据迭代,它已经按线性顺序排列,并且键只需要用于特定值,因此我认为没有必要展平整个数组。 - hakre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接