【问题标题】:PHP - Create Hierarchal ArrayPHP - 创建层次数组
【发布时间】:2012-01-29 10:51:14
【问题描述】:

我什至不知道如何开始措辞这个问题,但基本上,我有一个数组,看起来像这样:

Array
(
    [0] => /
    [1] => /404/
    [2] => /abstracts/
    [3] => /abstracts/edit/
    [4] => /abstracts/review/
    [5] => /abstracts/view/
    [6] => /admin/
    [7] => /admin/ads/
    [8] => /admin/ads/clickcounter/
    [9] => /admin/ads/delete/
    [10] => /admin/ads/edit/
    [11] => /admin/ads/list/
    [12] => /admin/ads/new/
    [13] => /admin/ads/sponsordelete/
    [14] => /admin/ads/sponsoredit/
    [15] => /admin/ads/sponsornew/
    [16] => /admin/ads/stats/
    [17] => /admin/boilerplates/
    [18] => /admin/boilerplates/deleteboiler/
    [19] => /admin/boilerplates/editboiler/
    [20] => /admin/boilerplates/newboilerplate/
    [21] => /admin/calendar/event/add/
    [22] => /admin/calendar/event/copy/
)

我需要将它“减少”/“处理”成一个如下所示的数组:

Array
(
    [''] => Array()
    ['404'] => Array()
    ['abstracts'] => Array
                     (
                          [''] => Array()
                          ['edit'] => Array()
                          ['review'] => Array()
                          ['view'] => Array()
                     )
    ['admin'] => Array
                     (
                          ['ads'] => Array
                                     (
                                         [''] => Array()
                                         ['clickcounter'] => Array()
                                         ['delete'] =>Array()
                                         ['edit'] => Array()
                                     )
                     )
    .....
    .....   
)

如果手动初始化会是这样的:

$urlTree = array( ''         => array(),
                  '404'      => array(),
                  'abstracts'=> array( ''      => array(),
                                       'edit'  => array(),
                                       'review'=> array(),
                                       'view'  => array() ),
                  'admin'    => array( 'ads'=> array( ''            => array(),
                                                      'clickcounter'=> array(),
                                                      'delete'      => array(),
                                                      'edit'        => array() ) )
);

我通常不会直接询问 SO 上的一大段代码,但是否有人可能有任何建议/代码可以遍历我的数组并将其转换为层次结构?

编辑:这是我现在拥有的一点,我知道这太少了,我今天似乎只是空白。

  function loadUrlData()
  {
    // hold the raw data, /blah/blah/
    $urlData = array();

    $res = sql::query( "SELECT DISTINCT(`url`) FROM `pages` ORDER BY `url` ASC" );
    while( $row = sql::getarray( $res ) )
    {
      $urlData[] = explode( '/', substr( $row['url'], 1, -1 ) );
    }

    // populated, eventually, with the parent > child data
    $treeData = array();

    // a url
    foreach( $urlData as $k=> $v )
    {
      // the url pieces
      foreach( $v as $k2=> $v2 )
      {

      }
    }

    // $treeData eventually
    return $urlData;
  }

【问题讨论】:

  • 不应该把404、abstract等所有的url都放在''里面吗?

标签: php arrays recursion tree


【解决方案1】:

看起来很简单。您想遍历所有行 (foreach),将它们拆分为部分 (explode),遍历它们 (foreach) 并对其进行分类。

既然你不喜欢要一大段代码,那我就不提供了。

更新
解决这个问题的一个非常好的方法是引用$urlTree(使用&),遍历URL 的每个部分,并不断更新像$currentPosition 这样的变量到URL 树中的当前部分。因为您使用&,所以您可以直接编辑数组,同时仍然使用一个简单的变量。

更新 2
这可能有效:

// a url
foreach( $urlData as $k=> $v )
{
  $currentSection = &$treeData;
  // the url pieces
  foreach( $v as $k2=> $v2 )
  {
    if (!isset($currentSection[$v2])) {
      $currentSection[$v2] = array();
    }

    $currentSection = &$currentSection[$v2];
  }
}

【讨论】:

  • 这正是我现在所处的位置,但我觉得我需要某种递归方法将它们放入正确的插槽中。我不害怕递归或任何东西,我工作了一段时间后,我有点沮丧。
  • 另外,我已经更新了我的问题以包括我现在拥有的内容,而不是说它是远程实质性的。
  • 我认为答案现在就在我的答案中。它可能会工作(它未经测试,我什至不确定这在 PHP 中是否有效)
  • 那位先生,是一个非常优雅的解决方案。我是如此专注于使用递归,我什至没有想过要在我的循环中获取一个“引用”。
【解决方案2】:

http://ideone.com/S9pWw

$arr = array(
    '/',
    '/404/',
    '/abstracts/',
    '/abstracts/edit/',
    '/abstracts/review/',
    '/abstracts/view/',
    '/admin/',
    '/admin/ads/',
    '/admin/ads/clickcounter/',
    '/admin/ads/delete/',
    '/admin/ads/edit/',
    '/admin/ads/list/',
    '/admin/ads/new/',
    '/admin/ads/sponsordelete/',
    '/admin/ads/sponsoredit/',
    '/admin/ads/sponsornew/',
    '/admin/ads/stats/',
    '/admin/boilerplates/',
    '/admin/boilerplates/deleteboiler/',
    '/admin/boilerplates/editboiler/',
    '/admin/boilerplates/newboilerplate/',
    '/admin/calendar/event/add/',
    '/admin/calendar/event/copy/');

$result = array();
foreach ($arr as $node) {
    $result = magic($node, $result);
}

var_dump($result);

function magic($node, $tree)
{
    $path = explode('/', rtrim($node, '/'));

    $original =& $tree;

    foreach ($path as $node) {
        if (!array_key_exists($node, $tree)) {
            $tree[$node] = array();
        }

        if ($node) {
            $tree =& $tree[$node];
        }
    }

    return $original;
}

【讨论】:

    【解决方案3】:

    您可以考虑将文本转换为JSON 字符串,然后使用 json_decode() 生成结构。

    【讨论】:

      【解决方案4】:

      我的版本:

      $paths = array(
          0 => '/',
          1 => '/404/',
          2 => '/abstracts/',
          3 => '/abstracts/edit/',
          4 => '/abstracts/review/',
          5 => '/abstracts/view/',
          6 => '/admin/',
          7 => '/admin/ads/',
          // ....
      );
      $tree = array();
      foreach($paths as $path){
          $tmp = &$tree;
          $pathParts = explode('/', rtrim($path, '/'));
          foreach($pathParts as $pathPart){
              if(!array_key_exists($pathPart, $tmp)){
                  $tmp[$pathPart] = array();
              }
              $tmp = &$tmp[$pathPart];
          }
      }
      
      echo json_encode($tree, JSON_PRETTY_PRINT);
      

      https://ideone.com/So1HLm

      【讨论】:

        【解决方案5】:

        我知道你并没有要求一大段代码,但我只是称之为小服务:

        $map = array();
        foreach($urls as $url) {
            $folders = explode('/', trim($url, '/'));
        
            applyChain($map, $folders, array());
        }
        
        function applyChain(&$arr, $indexes, $value) { //Here's your recursion
            if(!is_array($indexes)) {
                return;
            }
        
            if(count($indexes) == 0) {
                $arr = $value;
            } else {
                applyChain($arr[array_shift($indexes)], $indexes, $value);
            }
        }
        

        这很简单。我们将每个 url 分成其文件夹(删除尾部和前导斜杠),然后沿着数组链向下工作,直到到达 URL 中提到的文件夹。然后我们在那里放置一个新的空数组并继续下一个 URL。

        【讨论】:

          【解决方案6】:
          <?php
          $old_array = array("/", "/404/", "/abstracts/", "/abstracts/edit/", "/abstracts/review/", "/rrl/");
          $new_array = array();
          
          foreach($old_array as $woot) {
              $segments = explode('/', $woot);
              $current = &$new_array;
              for($i=1; $i<sizeof($segments); $i++) {
                  if(!isset($current[$segments[$i]])){
                      $current[$segments[$i]] = array();
                  }
                  $current = &$current[$segments[$i]];
              }
          }
          
          print_r($new_array);
          
          ?>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-06-07
            • 2011-06-18
            • 2019-03-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多