【问题标题】:How to recursively build a <select> with unknown tree depth如何递归构建具有未知树深度的 <select>
【发布时间】:2012-04-04 12:34:28
【问题描述】:

我有一个带有树形数据结构的 MySQL 表。这些字段是_idnameparentId。当记录没有父记录时,parentId 默认为 0。这样我可以构建一个数组,然后递归打印每条记录。

构建的数组如下所示:

Array
(
    [1] => Array
        (
            [parentId] => 0
            [name] => Countries
            [_id] => 1
            [children] => Array
                (
                    [2] => Array
                        (
                            [parentId] => 1
                            [name] => America
                            [_id] => 2
                            [children] => Array
                                (
                                    [3] => Array
                                        (
                                            [parentId] => 2
                                            [name] => Canada
                                            [_id] => 3
                                            [children] => Array
                                                (
                                                    [4] => Array
                                                        (
                                                            [parentId] => 3
                                                            [name] => Ottawa
                                                            [_id] => 4
                                                        )

                                                )

                                        )

                                )

                        )

                    [5] => Array
                        (
                            [parentId] => 1
                            [name] => Asia
                            [_id] => 5
                        )

                    [6] => Array
                        (
                            [parentId] => 1
                            [name] => Europe
                            [_id] => 6
                            [children] => Array
                                (
                                    [7] => Array
                                        (
                                            [parentId] => 6
                                            [name] => Italy
                                            [_id] => 7
                                        )

                                    [11] => Array
                                        (
                                            [parentId] => 6
                                            [name] => Germany
                                            [_id] => 11
                                        )

                                    [12] => Array
                                        (
                                            [parentId] => 6
                                            [name] => France
                                            [_id] => 12
                                        )

                                )

                        )

                    [8] => Array
                        (
                            [parentId] => 1
                            [name] => Oceania
                            [_id] => 8
                        )

                )

         )

 )

使用递归打印无序列表&lt;ul&gt; 非常简单。这是我使用的功能:

function toUL ($arr) {

    $html = '<ul>' . PHP_EOL;

    foreach ( $arr as $v ) {

        $html.= '<li>' . $v['name'] . '</li>' . PHP_EOL;

        if ( array_key_exists('children', $v) ) {
            $html.= toUL($v['children']);
        }

    }

    $html.= '</ul>' . PHP_EOL;

    return $html;
}

但我坚持以树结构的方式打印&lt;select&gt;

Countries
-- America
---- Canada
------ Ottawa
-- Asia
-- Europe
---- Italy
---- Germany
---- France
-- Oceania

我想打印-- 与元素深度一样多,但我不知道如何计算深度。

我的问题是:是否可以在不知道深度的情况下构建&lt;select&gt;

提前谢谢你。

【问题讨论】:

  • 是否可以向数据库添加深度字段?然后在创建时将其设置为父深度 + 1?
  • 当然可以,但我想避免添加新字段

标签: php recursion tree


【解决方案1】:

传递一个参数来计算迭代次数,如$pass

function toUL ($arr, $pass = 0) {

    $html = '<ul>' . PHP_EOL;

    foreach ( $arr as $v ) {           

        $html.= '<li>';
        $html .= str_repeat("--", $pass); // use the $pass value to create the --
        $html .= $v['name'] . '</li>' . PHP_EOL;

        if ( array_key_exists('children', $v) ) {
            $html.= toUL($v['children'], $pass+1);
        }

    }

    $html.= '</ul>' . PHP_EOL;

    return $html;
}

【讨论】:

  • @varan,不,你错了,没看到代码吗?它首先检查children 索引是否有数组,然后通过。
  • foreach ( $arr as $v ) { // 如果你第二次到达这个循环点,深度将是相同的,但 $pass 可以从之前的迭代中改变。跨度>
  • @varan,这意味着要发生,以跟踪项目的级别。
  • $pass++ 应该替换为 $pass+1
  • 为什么这么复杂,PHP has that already build in
【解决方案2】:

您的问题已在 SPL 中解决。 RecursiveIteratorIteratorDocs 有关于一个项目的深度的信息:

$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), SELF_FIRST);
foreach ($it as $key => $element)
{
    if ($key !== 'name') continue;
    $inset = str_repeat('--', $it->getDepth());
    printf('<option>%s %s</option>', $inset, $element);
}

【讨论】:

  • 拿出我看到的锤子:P
  • 是的,但有一些缺陷,未经测试;)
  • 我知道我正在用拇指敲锤子,但是 +1
【解决方案3】:
function toSelect($arr, $depth = 0) {

    $html = '';

    foreach ( $arr as $v ) {           

        $html.= '<option>' . str_repeat("--", $depth) . $v['name'] . '</option>' . PHP_EOL;

        if ( array_key_exists('children', $v) ) {
            $html.= toSelect($v['children'], $depth++);
        }

    }


    return $html;
}

【讨论】:

    【解决方案4】:

    我的最终解决方案(感谢 Starx 和 varan):

    function toSelect ($arr, $depth=0) {    
        $html = '';
        foreach ( $arr as $v ) {
    
            $html.= '<option value="' . $v['_id'] . '">';
            $html.= str_repeat('--', $depth);
            $html.= $v['name'] . '</option>' . PHP_EOL;
    
            if ( array_key_exists('children', $v) ) {
                $html.= toSelect($v['children'], $depth+1);
            }
        }
    
        return $html;
    }
    
    echo '<select>';
    echo toSelect($array);
    echo '</select>';
    

    即使RecursiveIteratorIterator 解决方案也很好(感谢 hakre)。

    【讨论】:

      【解决方案5】:

      嗨,伙计们,您可以这样做: 我有 $tree 的这个对象:

         Array
      (
          [0] => stdClass Object
              (
                  [id] => 1
                  [nombre] => Category 1
                  [subcategorias] => Array
                      (
                          [0] => stdClass Object
                              (
                                  [id] => 4
                                  [nombre] => Category 1.1
                              )
      
                      )
      
              )
      
          [1] => stdClass Object
              (
                  [id] => 2
                  [nombre] => Category 2
              )
      
          [2] => stdClass Object
              (
                  [id] => 3
                  [nombre] => Category 3
                  [subcategorias] => Array
                      (
                          [0] => stdClass Object
                              (
                                  [id] => 5
                                  [nombre] => Category 3.1
                                  [subcategorias] => Array
                                      (
                                          [0] => stdClass Object
                                              (
                                                  [id] => 6
                                                  [nombre] => Category 3.1.1
                                              )
      
                                      )
      
                              )
      
                      )
      
              )
      
      )
      

      下面是如何为 HTML 选择创建数组:

          $tree=array();// PUT HERE YOUR TREE ARRAY
          $arrayiter = new RecursiveArrayIterator($tree);
          $iteriter = new RecursiveIteratorIterator($arrayiter);
          $lista=array();
          $i=0;
          foreach ($iteriter as $key => $value) 
          {
              $id=$iteriter->current();
              $iteriter->next();
              $nivel=$iteriter->getDepth();
              $nombre=str_repeat('-',$nivel-1).$iteriter->current();
              $lista[$id]=$nombre;
          }
      

      你会得到这样的东西:

          Array
      (
          [1] => Category 1
          [4] => --Category 1.1
          [2] => Category 2
          [3] => Category 3
          [5] => --Category 3.1
          [6] => ----Category 3.1.1
      )
      

      然后您只需要使用简单的 foreach 为选择创建选项。

      【讨论】:

      • 你看过其他 7 个答案了吗?
      • 嗨@RichardTheKiwi,与hakre 非常相似,不同之处在于将最终数组作为键=> 用于创建选项并将ID 存储在数据库中的值。
      【解决方案6】:

      您可以将长度传递给函数并在递归调用时将其递增,然后使用变量$length 来确定深度

      function toUL ($arr, $length = 0) {
      
          $html = '<ul>' . PHP_EOL;
      
          foreach ( $arr as $v ) {
      
              $html.= '<li>' . $v['name'] . '</li>' . PHP_EOL;
      
              if ( array_key_exists('children', $v) ) {
                  $html.= toUL($v['children'], $length++);
              }
      
          }
      
          $html.= '</ul>' . PHP_EOL;
      
          return $html;
      }
      

      这是我通常用来跟踪递归深度的方法,它通常可以完成工作

      【讨论】:

        【解决方案7】:
        function toUL ($arr, $depth = 0) {
        //    ...
        $html .= toUL($v['children'], $depth+1);
        

        【讨论】:

          【解决方案8】:

          您可以使用 optgroup 作为迭​​代器。 例如:

          <select name="list">
            <option value=1>1st option</option>
            <optgroup>
              <option value=10>1st on 1st group</option>
            </optgroup>
          </select>
          

          如果你想要php,你可以试试这个:

          <?PHP
          function toSELECT($arr,$depth=0)
          {
          $html="";
          if(is_array($arr))
              {
              $html.=($depth==0)?"<select name='html'>\n":"";
              foreach ($arr as $key=>$value)
                  {
                  if(is_array($arr[$key]))
                      {
                      $html.=str_repeat("\t",$depth)."<optgroup>\n";
                      $html.=str_repeat("\t",$depth).toHTML($arr[$key],$depth+1);
                      $html.=str_repeat("\t",$depth)."</optgroup>\n";
                      }
                  else
                      {
                      $html.=str_repeat("\t",$depth)."<option value='".$value."'>".$key."</option>\n";
                      }
                  }
              $html.=($depth==0)?"</select>\n":"";
              }
          return $html;
          }
          
          ?>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-10-08
            • 2020-10-17
            • 2021-10-09
            • 1970-01-01
            • 2016-11-16
            • 1970-01-01
            • 2018-05-07
            • 2021-07-11
            相关资源
            最近更新 更多