【问题标题】: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()

标签: php arrays recursion


【解决方案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'

      【讨论】:

      • 这不符合问题的要求。或者不清楚。
      • 你说得对,重新阅读帖子后,我认为不应删除“内容”数组,无论是否为空。我刚刚调整了代码,但可能仍然误解了帖子。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-05
      • 2021-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多