使用RecursiveArrayIterator获取所有父节点

时间:2012-11-29 15:35:35

标签: php optimization spl

基本上,我想使用

$foo = new RecursiveIteratorIterator(new RecursiveArrayIterator($haystack));

方法论,但不是为foreach()返回一个平面数组,而是保留结构,但只返回一个伟大的子孙节点及其父节点。这可能在PHP吗?


我的任务是优化我公司的一些(可怕的)代码库。我发现了一个通过数组递归,搜索密钥的函数。我无法用简单的array_search()array_key_exists()替换它,因为自定义函数还返回匹配(找到)键的父节点,而不仅仅是{{ 1}}或true

如何使用falseRecursiveArrayIterator或者使用其他内置函数(即尽可能少的自定义代码)来从搜索数组中返回匹配节点的父树?我想获得最快的功能,因为目前这个函数花费8秒执行14000次,因此我需要使用内置函数。

我现有的尝试(下面)速度非常慢。

RecursiveIteratorIterator

function search_in_array($needle, $haystack) { $path = array(); $it = new RecursiveArrayIterator($haystack); iterator_apply($it, 'traverse', array($it, $needle, &$path)); return $path; } function traverse($it, $needle, &$path) { while($it->valid()) { $key = $it->key(); $value = $it->current(); if(strcasecmp($value['id'], $needle) === 0) { $path[] = $key; return; } else if($it->hasChildren()) { $sub = null; traverse($it->getChildren(), $needle, &$sub); if($sub) { $path[$key] = $sub; } } $it->next(); } } 的示例输出如下所示:

$needle = TVALL

搜索数组看起来像这样(对于广泛的抱歉)。有两个以上的顶级节点,但我为了简洁而截断了它:

Array (
    [HOMECINEMA] => Array (
        [children] => Array (
            [HC-VISION] => Array (
                [children] => Array (
                    [0] => TVALL
                )
            )
        )
    )
)

1 个答案:

答案 0 :(得分:6)

下面的示例不一定具有更高的性能(在时间或内存要求中),但避免在结构中手动递归,并显示更容易(IMHO)方式来构建所需的输出数组。

function search_in_array($needle, $haystack) {
    $path = array();

    $it = new RecursiveIteratorIterator(
        new ParentIterator(new RecursiveArrayIterator($haystack)),
        RecursiveIteratorIterator::SELF_FIRST
    );

    foreach ($it as $key => $value) {
        if (array_key_exists('id', $value) && strcasecmp($value['id'], $needle) === 0) {
            $path = array($needle);
            for ($i = $it->getDepth() - 1; $i >= 0; $i--) {
                $path = array($it->getSubIterator($i)->key() => $path);
            }
            break;
        }
    }

    return $path;
}

<强>参考

<强>加成

如果您的数组也更深入,您还可以使用RecursiveIteratorIterator::setMaxDepth()方法将递归限制为n级别。