PHP如何遍历层次扁平数组?

3

我有一个数据集,它是一个扁平的、分层的多维数组:

[
    [
        'title' => 'Skylake',
        'type' => 'category',
        'items' => 
        [
            [
                'title' => 'Core i3',
                'type' => 'category',
                'items' => 
                [
                    [
                        'title' => '6100',
                        'type' => 'product',
                        'price' => 100.0,
                    ],
                    [
                        'title' => '6300',
                        'type' => 'product',
                        'price' => 110.0,
                    ],
                ],
            ],
            [
                'title' => 'Core i7',
                'type' => 'category',
                'items' => [
                    [
                        'title' => '7700',
                        'type' => 'product',
                        'price' => 330.0,
                    ],
                    [
                        'title' => '7700K',
                        'type' => 'product',
                        'price' => 370.0,
                    ],
                ],
            ],
        ],
    ],
    [
        'title' => 'KabyLake',
        'type' => 'category',
    ]
];

正如您所看到的,有两个主要类别:Skylake和Kabylake,它们包含其他子类别,而这些子类别又包含产品。

我试图遍历这个扁平数组,但出现了一些问题,因为'core i7'类别将不知道其父类别是'Skylake'。 当我将数据插入数据库时,其parent_id将为空。

   /**
     * Creates catalog.
     * @param mixin $sampleItems sample items
     * @param interger $categoryId id of category (parent id)
     */
    private function createCatalog(&$sampleItems, $categoryId = null)
    {
        foreach ($sampleItems as $sampleItem) {
            if ($sampleItem['type'] == 'category') {
                $categoryId = $this->createCategory($sampleItem, $categoryId);
            } else {
                $this->createProduct($sampleItem, $categoryId);
            }
            $hasItems = isset($sampleItem['items']) && is_array($sampleItem['items']);
            if ($hasItems) {
                $this->createCatalog($sampleItem['items'], $categoryId);
                $categoryId = null;
            }
        }
    }

    /**
     * Create category.
     * @param mixin $sampleData
     * @param integer $parentId ID of parent category
     * @return integer ID of created category
     */
    private function createCategory($sampleData, $parentId)
    {
        $category = new Category();
        if ($parentId !== null) {
            $category->parent_id = $parentId;
        }
        $category->title = $sampleData['title'];
        $category->status = 1;
        $category->save();

        return $category->id;
    }

    /**
     * Create Product.
     * @param mixin $sampleData
     * @param integer $categoryId
     */
    private function createProduct($sampleData, $categoryId)
    {
        $product = new Product();
        if ($categoryId !== null) {
            $product->category_id = $categoryId;
        }
        $product->title = $sampleData['title'];
        $product->price = $sampleData['price'];
        $product->description = $sampleData['description'];
        $product->status = 1;
        $product->save();
    }

很遗憾,这是当前数据库中的层次结构:

Skylake
  Core i3
Core i7
KabyLake

Core i7应该属于Skylake系列。

我认为问题在于Core i7的$parentId为空值。

但我不知道原因所在。


4
我不同意你的术语。 "平面"和"分层"是互斥的。你拥有的是一个关联数组图 - 根本不是“平面”的。 - Dai
分类可以有多少层深度?如果一个分类可以包含另一个分类,而该分类又包含另一个分类(以此类推),那么您需要使用图遍历算法,例如递归函数或使用堆栈进行BFS或DFS遍历。 - Dai
@Dai 看起来 createCatalog 是递归的。 - Don't Panic
@Don'tPanic 啊,真是鹰眼!我一开始没看到。 - Dai
@Dai,你说得对,现在我学会了正确的英语单词来描述这个问题:)。我完全忘记它叫什么了。我在谷歌上搜索了(平面、分层词汇)。我的母语不属于印欧语系。非常抱歉。 - stecker
1个回答

4
问题在于您在循环中为当前分类的父级和创建的子分类的父级使用相同的变量$categoryId。 当您在创建嵌套目录后执行$categoryId = null;,那会影响下一次调用createCategory()
请使用不同的变量,我在下面使用$subcat
private function createCatalog(&$sampleItems, $categoryId = null)
{
    $subcat = null;
    foreach ($sampleItems as $sampleItem) {
        if ($sampleItem['type'] == 'category') {
            $subcat = $this->createCategory($sampleItem, $categoryId);
        } else {
            $this->createProduct($sampleItem, $categoryId);
        }
        $hasItems = isset($sampleItem['items']) && is_array($sampleItem['items']);
        if ($hasItems) {
            $this->createCatalog($sampleItem['items'], $subcat);
            $subcat = null;
        }
    }
}

你的意思是这会影响下一次调用 createCatalog 吗? - Cave Johnson
不,我的意思是下一个 $categoryId = $this->createCategory($sampleItem, $categoryId); - Barmar

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