从类别树中清除空类别

Posted

技术标签:

【中文标题】从类别树中清除空类别【英文标题】:Cleanup empty categories from category tree 【发布时间】:2021-12-10 19:32:53 【问题描述】:

我创建了一个类别树,其中每个类别都包含子类别,每个类别都包含其关联的内容。此树中的某些类别包含子类别但没有关联的内容。如何清理类别树以使树结构仅包含具有关联内容的类别或具有关联内容的子类别的类别?也就是说,在类别树中,应该只存在通向具有相关内容的类别的路径。

我的结构是一个数组:

[uid_of_category]
   => (array)content
      => empty
   => (array)sub_categories
      => [uid_of_category]
         => (array)content
             => empty
         => (array)sub_categories
      => [uid_of_category]
         => (array)content
             => [...associated content...]
         => (array)sub_categories
 [uid_of_category]
   => (array)content
      => empty
   => (array)sub_categories
      => [uid_of_category]
         => (array)content
             => [...associated content...]
         => (array)sub_categories
      => [uid_of_category]
         => (array)content
             => empty
         => (array)sub_categories
            => [uid_of_category]
               => (array)content
                 => [...associated content...]
            => (array)sub_categories
               ...

我尝试使用递归函数下到树的最低元素,但我不知道如何实现,即使那些元素仍保留在树中,没有相关内容,但其子元素有相关内容。

【问题讨论】:

显示一些代码,你试过什么?类别结构是数组吗...需要更多信息。 您能否发布一个示例数组的var_dump() 【参考方案1】:

据我了解您的要求,您有一棵树,您想清理它,以免没有叶子的树枝留在里面。

在这种情况下,我想提出一个通用的解决方案,无论您选择什么键名都可以使用。该解决方案基于array_walk() 和array_walk_recursive() 函数。第一个允许在树(或树枝)上行走,第二个允许计算树(或树枝)中的叶子数,无论其中的维数如何。

这是一个命题:

function cleanTree($tree, $cleanTree = []) 

    // Walk the tree
    array_walk($tree, function ($branch, $node) use (&$cleanTree) 

        // Here is a leaf (the lowest element in the tree), we keep it
        if (!is_array($branch)) 
            $cleanTree[$node] = $branch;

        // Here is a branch that may contain some leafs
         else 

            // Count the leafs of this branch
            $leafs = 0;
            array_walk_recursive($branch, function () use (&$leafs)  $leafs++; );

            // There is at least one leaf on this branch, so we walk it
            if ($leafs) 
                $cleanTree[$node] = cleanTree($branch);
            
        

    );

    return $cleanTree;


使用此功能,所有没有叶子的分支都不会保留。

将你的树声明为一个数组然后清理它:

$myTree = [...];
$myCleanTree = cleanTree($myTree);

我使用@lukas.j 提供的数组示例进行了尝试(感谢您的努力)并且成功了。

【讨论】:

【参考方案2】:

这种情况最好通过树的后序遍历来解决。

在后序遍历中,您希望首先对所有子树进行递归。然后在当前节点上做需要的操作。

function cleanUp(&$categories) 
    if (empty($categories)) 
        //no categories, nothing to do here
        return;
    

    foreach ($categories as $key => &$category) 
        //first clean up sub categories
        cleanUp($category['sub_categories']);
 
        if (empty($category['sub_categories']) && empty($category['content'])) 
            //If there are no sub_categories left and there is no content remove category
            unset($categories[$key]);
        
    

在对子类别进行清理之后,您知道如果还剩下任何子类别,则它们必须有内容或带有内容的子类别。因此,此时您可以轻松决定是否需要删除当前类别。

【讨论】:

【参考方案3】:

显然,递归会有所帮助。但是让我们使用两个函数而不是一个。我们将使用一个函数来确定一个类别是否满足要清理(删除)的条件。清洁的另一个功能。在这个函数中,参数将通过引用(&$categories)传递。所有这些都假设结构是一个数组。

cleanCategories($categories);

function cleanCategories(&$categories)

    foreach ($categories as $key=>&$category) 
        if (isCleanable($category)) 
            unset($categories[$key]);
         else 
            cleanCategories($category['sub_categories']);
        
    


function isCleanable($category)

    if (!empty($category['content'])) 
        return false;
    

    foreach ($category['sub_categories'] as $category) 
        if (!isCleanable($category)) 
            return false;
        
    

    return true;

通过这种方法,您可以做出更好、更有效的解决方案。

别忘了 Stack Overflow 不是一个编写代码的服务。你必须自己思考,再思考,找到方法(只是思考),放入代码,尝试代码,调试代码......

【讨论】:

isCleanable 中有拼写错误:sub_categies @lukas.j 谢谢,我修好了。 你在某个地方需要一个额外的& @SalmanA 欢迎您的编辑,谢谢!【参考方案4】:

试图根据OP的帖子构建一个数组:

$arr = [
    "uid_of_category_0" => [
        "content"        => [],
        "sub_categories" => [
            "uid_of_category_0_0" => [
                "content"        => [],
                "sub_categories" => []
            ],
            "uid_of_category_0_1" => [
                "content"        => [
                    "associated_content_0_1_0",
                    "associated_content_0_1_1",
                    "associated_content_0_1_2"
                ],
                "sub_categories" => []
            ]
        ]
    ],
    "uid_of_category_1" => [
        "content"        => [],
        "sub_categories" => [
            "uid_of_category_1_0" => [
                "content"        => [
                    "associated_content_1_0_0",
                    "associated_content_1_0_1",
                    "associated_content_1_0_2"
                ],
                "sub_categories" => []
            ],
            "uid_of_category_1_1" => [
                "content"        => [],
                "sub_categories" => [
                    "uid_of_category_1_1_0" => [
                        "content"        => [
                            "associated_content_1_1_0_0",
                            "associated_content_1_1_0_1",
                            "associated_content_1_1_0_2"
                        ],
                        "sub_categories" => []
                    ]
                ]
            ]
        ]
    ],
];

这将是取消设置 $arr 中所有空数组的代码:

function unset_empty_arrays(array $arr): array 
  foreach (array_keys($arr) as $key) 
    if (is_array($arr[$key])) 
      $arr[$key] = unset_empty_arrays($arr[$key]);
    
    if ($arr[$key] === [] && $key === 'sub_categories') 
      unset($arr[$key]);
    
  
  return $arr;


print_r(unset_empty_arrays($arr));

编辑:添加 && $key === 'sub_categories'

【讨论】:

这不符合问题的要求。或者不清楚。 你说得对,重新阅读帖子后,我认为不应删除“内容”数组,无论是否为空。我刚刚调整了代码,但可能仍然误解了帖子。

以上是关于从类别树中清除空类别的主要内容,如果未能解决你的问题,请参考以下文章

sql 更改类别,这将清除“canuse”列,并在另一列中为您提供可用于分析的交叉CUC。

sql 更改类别,这将清除“canuse”列,并在另一列中为您提供可用于分析的交叉CUC。

单击时清除 CSS 菜单悬停状态(通过 ajax 加载的页面)

数据库更新后如何清除缓存?

如果选择了一个类别,如何在产品树中隐藏其他类别

CSS--清除浮动方法详解