PHP类别反向遍历算法

PHP类别反向遍历算法,php,arrays,algorithm,multidimensional-array,traversal,Php,Arrays,Algorithm,Multidimensional Array,Traversal,我正在尝试优化一个电子商务分类系统,该系统具有无限的分类深度(系统内存限制除外)。我一次检索所有类别,并将其排序为多维数组,大致如下所示: [array] ( [0] ( 'CategoryId' => 1, 'ParentCategoryId' => 0, 'Title' => 'Category A', 'SubCategories' => [array] ( [0] ( 'CategoryId' =&g

我正在尝试优化一个电子商务分类系统,该系统具有无限的分类深度(系统内存限制除外)。我一次检索所有类别,并将其排序为多维数组,大致如下所示:

[array] (
  [0] (
    'CategoryId' => 1,
    'ParentCategoryId' => 0,
    'Title' => 'Category A',
    'SubCategories' => [array] (
      [0] (
        'CategoryId' => 2,
        'ParentCategoryId' => 1,
        'Title' => 'Category B',
        'SubCategories' => [array] (
          [0] (
            'CategoryId' => 3,
            'ParentCategoryId' => 2,
            'Title' => 'Category C'
          )
        )
      )
    )
  )
)
数组中的每一项实际上都是一个对象,但为了简单起见,我把它写成了一种数组格式

我可以使用此功能向下遍历我的树:

/**
* Find Branch using Recursive search by Object Key
* @param String     Needle
* @param Array      Haystack
* @return Array
*/
public static function findBranchByKey($key, $needle, $haystack)
{
    foreach ($haystack as $item) 
    {
        if ( $item->$key == $needle || ( is_object($item) && $item = self::findBranchByKey($key, $needle, $item->SubCategories)) ) 
        {
            return $item;
        }
    }
    return false;
}
这将查找具有匹配键的对象并返回它(可能包含更多子类别)

我的问题是如何穿越另一个方向。例如,使用上面的数据,假设我正在显示“Category C”,并希望创建其父母的面包屑。我想不出一个好方法来获取我的数组,跳转到一个特定的子类别,然后向上迭代以获得每个父类。这样的结果数组可能是这样的,因此很容易将它们吐出作为面包屑:

 array( 'Category A', 'Category B', 'Category C' )
我可能可以在数据库中使用SQL来实现这一点,但我希望检索一次树,缓存它,并在需要时对该对象执行遍历,而不是进行大量查询


TL;博士如何在多维类别数组中向上遍历?

可以通过递归完成

比方说,这个函数应该可以工作:

function getPath($id, $tree, &$path = array()) {
    foreach ($tree as $item) {
        if ($item['CategoryId'] == $id) {           
            array_push($path, $item['CategoryId']);
            return $path;
        }
        if (!empty($item['SubCategories'])) {
            array_push($path, $item['CategoryId']);
            if (getPath($id, $item['SubCategories'], $path) === false) {
                array_pop($path);
            } else {
                return $path;
            }

        }
    }
    return false;
}
这:

将导致:

Array ( [0] => 1 [1] => 4 [2] => 5 )

它可以通过递归实现

比方说,这个函数应该可以工作:

function getPath($id, $tree, &$path = array()) {
    foreach ($tree as $item) {
        if ($item['CategoryId'] == $id) {           
            array_push($path, $item['CategoryId']);
            return $path;
        }
        if (!empty($item['SubCategories'])) {
            array_push($path, $item['CategoryId']);
            if (getPath($id, $item['SubCategories'], $path) === false) {
                array_pop($path);
            } else {
                return $path;
            }

        }
    }
    return false;
}
这:

将导致:

Array ( [0] => 1 [1] => 4 [2] => 5 )

节点树中的节点(这就是您在这里看到的)应该有一个对其父节点的引用,以及对其所有子节点的引用。您的每个类别似乎都有一个
ParentCategoryId
,我想您应该使用它:除了
ParentCategoryId
值之外,还有其他值吗?@cillos
ParentCategoryId
是一个整数,而不是一个引用。您可以有第二个数组,它是
categoryId=>node
的平面数组。这将允许您基于
categoryId
parentCategoryId
查找节点引用,而不必隐藏引用(例如,如果您尝试使用
print\r
打印它,这将导致递归问题)。您可以在对元素排序时构建查找表。您可以同样轻松地设置对父节点的引用,但正如我所说的,这将使您在使用某些PHP函数时遇到麻烦,例如
print\r
。节点树中的节点(这就是您在这里看到的)应该有对其父节点的引用,以及对其所有子类别的引用。您的每个类别似乎都有一个
父类别ID
,我想您会使用它:除了
ParentCategoryId
值之外,还有其他值吗?@cillos
ParentCategoryId
是一个整数,而不是一个引用。您可以有第二个数组,它是
categoryId=>node
的平面数组。这将允许您基于
categoryId
parentCategoryId
查找节点引用,而不必隐藏引用(例如,如果您尝试使用
print\r
打印它,这将导致递归问题)。您可以在对元素排序时构建查找表。您可以同样轻松地设置对父节点的引用,但正如我所说的,这将使您在使用某些PHP函数时遇到麻烦,例如
print\r
+1绝对出色!出于某种原因,我无法找到一个好的方法来进行递归。我真的需要把这类东西打包成一个很好的可重用类并共享它。再次感谢!很高兴听到,@cillosis:)+1绝对精彩!出于某种原因,我无法找到一个好的方法来进行递归。我真的需要把这类东西打包成一个很好的可重用类并共享它。再次感谢!很高兴听到,@cillosis:)