从MySQL结果创建分层数组

3

我看到了其他关于这个问题的提问,但并不完全像我的情况。我在MySQL中有以下表:

   term_id       name           slug                 taxonomy     parent
1             Entry Form     entry-form           format       0
2             Page           page                 format       3
3             Facebook       facebook             format       0
4             Entry Form     facebook-entry-form  format       3
5             Twitter        twitter              format       0
6             Single        single                format       2

我有以下的OBJECT查询:
$formats = $wpdb->get_results($wpdb->prepare("
    SELECT * FROM table t
    WHERE t.taxonomy = 'format'
"));

我得到了以下数组:

Array ( [0] => stdClass Object ( [term_id] => 1 [name] => Entry Form [slug] => entry-form [taxonomy] => format [parent] => 0 ) [2] => stdClass Object ( [term_id] => 2 [name] => Page [slug] => page [taxonomy] => format [parent] => 3 ) [3] => stdClass Object ( [term_id] => 3 [name] => Facebook [slug] => facebook [taxonomy] => format [parent] => 0 ) [4] => stdClass Object ( [term_id] => 4 [name] => Entry Form [slug] => entry-form-facebook [taxonomy] => format [parent] => 3 ) [5] => stdClass Object ( [term_id] => 5 [name] => Twitter [slug] => twitter [taxonomy] => format [parent] => 0 ) [6] => stdClass Object ( [term_id] => 6 [name] => Single [slug] => single [taxonomy] => format [parent] => 2 ) ) 1

所有上述内容需要转换成分层列表输出,看起来像这样:
Entry Form
Twitter
Facebook
 - Entry Form
 - Page
 -- Single

因此,我需要根据父字段将数组$ formats转换为分层数组。 0的父项表示它是顶级项目。 因此,由于Single具有父级2,因此它是Page的子项,后者又具有父级3并且是Facebook的子项。
谁能帮助我将我的数组转换为分层数组,然后向我展示如何通过循环进行输出?

也许你已经解释过了,但我不明白你想要什么输出?你能描述一下输出的片段吗?你只想要分层形式的名称还是所有数据? - Bhavik Shah
我希望输出的结果与以下描述完全一致:一个分层列表,类似于 <ul> <li>输入表单</li> <li>Twitter</li> <li>Facebook<ul> <li>页面 <ul> <li>单个</li> </ul> </li> </ul> </li> </ul> - Sweepster
2个回答

0

当你从数据库中获取数据时,需要将其放入关联数组中:

//$groups - result array

$groups = array();

//$record contains the assoc array of the current record
while($record = $result->fetchAssoc()) {
      if (!isset($groups[$record["parent"]]))
      {
            $groups[$record["parent"]] = array();
      }

      array_push($groups[$record["parent"]], $record);
}

最终你会得到一个以父级为键的层次结构的关联数组。然后通过递归遍历它,你就能得到结果:
function print_recursively(&$groups, $parent_id, $dashes = '')
{
    if(isset($groups[$parent_id]))
    {
          foreach($groups[$parent_id] as $key => $value)
          {
                print $dashes . ' ' . $value["name"];
                print_recursively(&$groups, $value["term_id"], $dashes . '-');
          }
    }
}

我没有测试过这段代码,但是算法是正确的。


这个概念对我来说完全是新的。我甚至不知道从哪里开始编写这段代码。我没有认出任何变量是我使用过的。我的 $formats 变量应该放在哪里? - Sweepster
首先给我看一下代码,你是如何从数据库中提取数据的。我会尝试向你展示如何修改它。 - user4035
代码就在这里:$formats = $wpdb->get_results($wpdb->prepare(" SELECT * FROM table t WHERE t.taxonomy = 'format' ")); - Sweepster
你能修改这段代码,使得它可以按顺序逐行获取结果吗? - user4035

0
如果查询量不会成为问题,最简单的解决方案是,不要执行填充数组的单个查询,而是对于您分层树中的每个节点执行一个查询,在其中添加“AND parent = $id”,其中$id是当前节点的term_id。类似这样:
  1. 执行SELECT WHERE .... AND parent = 0;
  2. 对于1中的每个结果,$id = term_id,执行SELECT WHERE ... AND parent = $id
  3. 递归重复直到没有更多结果
如果性能是一个问题,您仍然可以将查询转储到数组中,并将相同的算法应用于该数组,但如果您确实有如此大量的数据,则很可能会遇到内存问题。

这让我觉得更加低效。原因是如果子查询嵌套达到20层,那么我不应该在数据库中运行如此多的查询。对我来说,这似乎是浪费带宽。 - Sweepster
这就是为什么我提到了性能和查询数量的评论。如果您有20层深度,但不会连续地为数千个用户运行算法,那么您就没问题了。但是,如果是这种情况,将整个结果倾倒到数组中可能会使您超出内存限制或产生分页问题。问题(和答案)的关键在于您需要使用的递归算法。 - palako
好的,我明白你的意思。不过我不知道你所说的递归是什么意思。不过我会去了解一下。 - Sweepster
递归是因为你创建了一个打印元素及其子元素的函数,并从中为每个子元素再次调用相同的函数,以便它们可以打印自己和它们的子元素。如果您不熟悉这个概念,请查阅相关资料,这在编程中是必须的。 - palako

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