在多维数组中搜索键/值对的递归并返回路径

时间:2014-08-01 18:56:42

标签: php recursion multidimensional-array

我正在研究导航结构。 我正在使用父模型,所以我将所有子导航节点放入一个数组并将它们附加到父导航。

数组结构如下所示:

$navigation = array(
    0 =>
        array(
            'id' => '2',
            'parent_id' => '0',
            'name' => 'abouts us',
            'subNavigation' =>
                array(
                    0 => array(
                        'id' => '3',
                        'parent_id' => '2',
                        'name' => 'Foo',
                        'subNavigation' =>
                            array(
                                0 => array(
                                    'id' => '4',
                                    'parent_id' => '3',
                                    'name' => 'test',
                                    'subNavigation' =>
                                        array(),
                                ),
                                1 => array(
                                    'id' => '5',
                                    'parent_id' => '3',
                                    'name' => 'bar',
                                    'subNavigation' =>
                                        array(),
                                ),
                            ),
                        ),
                ),
        ),
    1 =>
        array(
            'id' => '6',
            'parent_id' => '0',
            'name' => 'Foobar',
            'subNavigation' =>
                array(
                    0 => array(
                        'id' => '7',
                        'parent_id' => '6',
                        'name' => 'ASDF',
                        'subNavigation' =>
                            array(),
                    ),
                ),
        ),
);

现在我想搜索一个导航ID,例如ID = 5(Navigation-Name = bar),结果应该是这个子导航的数组。

结果:

$result = array(
    0 =>
        array(
            'id' => '2',
            'parent_id' => '0',
            'name' => 'abouts us',
            'subNavigation' =>
                array(
                    0 => array(
                        'id' => '3',
                        'parent_id' => '2',
                        'name' => 'Foo',
                        'subNavigation' =>
                            array(
                                0 => array(
                                    'id' => '5',
                                    'parent_id' => '3',
                                    'name' => 'bar',
                                    'subNavigation' =>
                                        array(),
                                ),
                            ),
                    ),
                ),
        ),
);

最快的方式是什么,递归函数将完成这项工作?

编辑: 我编辑导航节点5的parent_id ...其中是一个错误的parent_id

1 个答案:

答案 0 :(得分:1)

非常有趣的问题。这是一个解决方案:

function search($navitation_tree, $id, $temp_branch = array()) {
    for ($i = 0; $i < sizeof($navitation_tree); $i++) {
        $nav_element = $navitation_tree[$i];

        if($nav_element['parent_id'] === '0') {
            $temp_branch = array();
        } else if($i > 0) {
            for ($y = 0; $y < 1; $y++) {
                array_pop($temp_branch);
            }
        }

        $cloned_nav_element = array('id' => $nav_element['id'],
                                    'parent_id' => $nav_element['parent_id'],
                                    'name' => $nav_element['name'],
                                    'subNavigation' => array());
        $temp_branch[] = $cloned_nav_element;

        if($nav_element['id'] === $id) {
            return $temp_branch;
        }

        if(sizeof($nav_element['subNavigation'] > 0)) {
            $result = search($nav_element['subNavigation'], $id, $temp_branch);
        }

        if($result != null) {

            return $result;
        }
    }
}

function getNavigationBranch($navitation_tree, $id) {
    $branch = search($navitation_tree, $id);

    if($branch !== null) {
        $final_nav_element = array();
        foreach($branch as $temp_nav_element) {
            if(empty($final_nav_element)) {
                $final_nav_element = array(array_pop($branch));
            } else {
                $temp_nav_element = array_pop($branch);
                $temp_nav_element['subNavigation'] = $final_nav_element;
                $final_nav_element = array($temp_nav_element);
            }
        }

        return $final_nav_element;
    }
}

$result = getNavigationBranch($navigation, '5');

search函数在导航树中执行depth-first search(DFS)。一旦找到所需的id,它就会将路径(由有序的导航元素数组表示)返回到getNavigationBranch,它会将数据重新构造为您在问题中请求的格式,并返回它们(如果找不到id,它将返回null

顺便说一句,尽管在大型图表中搜索时DFS可能会出现问题,但我认为它在导航树的大多数情况下都能正常工作(如果不是全部的话)。

为了测试它,我使用了以下数据:

$navigation = array(
    0 =>
        array(
            'id' => '2',
            'parent_id' => '0',
            'name' => 'abouts us',
            'subNavigation' =>
                array(
                    0 => array(
                        'id' => '3',
                        'parent_id' => '2',
                        'name' => 'Foo',
                        'subNavigation' =>
                            array(
                                0 => array(
                                    'id' => '4',
                                    'parent_id' => '3',
                                    'name' => 'test',
                                    'subNavigation' =>
                                        array(),
                                ),
                                1 => array(
                                    'id' => '5',
                                    'parent_id' => '3',
                                    'name' => 'bar',
                                    'subNavigation' =>
                                        array(),
                                ),
                            ),
                        ),
                    1 => array(
                        'id' => '8',
                        'parent_id' => '2',
                        'name' => 'Foo',
                        'subNavigation' =>
                            array(
                                0 => array(
                                    'id' => '9',
                                    'parent_id' => '8',
                                    'name' => 'test',
                                    'subNavigation' =>
                                        array(),
                                ),
                                1 => array(
                                    'id' => '10',
                                    'parent_id' => '8',
                                    'name' => 'bar',
                                    'subNavigation' =>
                                        array(),
                                ),
                            ),
                        ),
                    2 => array(
                        'id' => '11',
                        'parent_id' => '2',
                        'name' => 'Foo',
                        'subNavigation' =>
                            array(
                                0 => array(
                                    'id' => '12',
                                    'parent_id' => '8',
                                    'name' => 'test',
                                    'subNavigation' =>
                                        array(),
                                ),
                                1 => array(
                                    'id' => '13',
                                    'parent_id' => '8',
                                    'name' => 'bar',
                                    'subNavigation' =>
                                        array(),
                                ),
                            ),
                        ),
                ),
        ),
    1 =>
        array(
            'id' => '6',
            'parent_id' => '0',
            'name' => 'Foobar',
            'subNavigation' =>
                array(
                    0 => array(
                        'id' => '7',
                        'parent_id' => '6',
                        'name' => 'ASDF',
                        'subNavigation' =>
                            array(),
                    ),
                ),
        ),
);

以下是一些测试结果:

$result = getNavigationBranch($navigation, '5');
var_dump($result);

以上产生:

array(1) {
  [0]=>
  array(4) {
    ["id"]=>
    string(1) "2"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(9) "abouts us"
    ["subNavigation"]=>
    array(1) {
      [0]=>
      array(4) {
        ["id"]=>
        string(1) "3"
        ["parent_id"]=>
        string(1) "2"
        ["name"]=>
        string(3) "Foo"
        ["subNavigation"]=>
        array(1) {
          [0]=>
          array(4) {
            ["id"]=>
            string(1) "5"
            ["parent_id"]=>
            string(1) "3"
            ["name"]=>
            string(3) "bar"
            ["subNavigation"]=>
            array(0) {
            }
          }
        }
      }
    }
  }
}

还有一个:

$result = getNavigationBranch($navigation, '13');
var_dump($result);

以上产生:

array(1) {
  [0]=>
  array(4) {
    ["id"]=>
    string(1) "2"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(9) "abouts us"
    ["subNavigation"]=>
    array(1) {
      [0]=>
      array(4) {
        ["id"]=>
        string(2) "11"
        ["parent_id"]=>
        string(1) "2"
        ["name"]=>
        string(3) "Foo"
        ["subNavigation"]=>
        array(1) {
          [0]=>
          array(4) {
            ["id"]=>
            string(2) "13"
            ["parent_id"]=>
            string(1) "8"
            ["name"]=>
            string(3) "bar"
            ["subNavigation"]=>
            array(0) {
            }
          }
        }
      }
    }
  }
}