2012-08-16 92 views
1

我有存储在数组中的数据集上的foreach循环父和子节点进行排序通过在PHP与父子IDS引用本身: idparent_idtitle等顶层有parent_id0,并且可以有无数的父子关系。递归函数来使用阵列

因此,我正在用递归函数中的foreach循环对这个数组进行排序,以检查每个数组元素与它的父元素,并且我认为我一直盯着这个方法太长了。

我确实以正确的顺序结束了元素,但我似乎无法让我的列表正确嵌套,这让我觉得这个方法并不真正起作用。

  • 这是最好的路线?
  • 我能做些什么来改善和修复这种方法
  • 我还可以申请另一个技巧吗?

这里是我的源:

<div> 
    <div>Subpages</div> 

    <ul> 
    <?php subPages($this->subpages->toArray(), 0) ?> 
    </ul> 
    <br> 
    <a href="javascript:;" onclick="">Add New Subpage</a> 
</div> 

<?php 
    function subPages($subpages, $parent){ 

     foreach($subpages as $key => &$page){ 

      $newParent = $page['id']; 

      //If the current page is the parrent start a new list 
      if($page['id'] == $parent) 
      { 
       //Echo out a new list 
       echo '<ul>'; 
       echo '<li class="collapsed">'; 
       echo '<a href="javascript:;" class="toggle">+</a>'; 
       echo '<a href="javascript:;" onclick="">'.$page['title'].'</a>';   

       subPages($subpages, $newParent); 

       echo '</li>'; 
       echo '</ul>'; 
      } 
      //If the page's parent id matches the parent provided 
      else if($page['parent_id'] == $parent) 
      { 
       //Echo out the link 
       echo '<li class="collapsed">'; 
       echo '<a href="javascript:;" class="toggle">+</a>'; 
       echo '<a href="javascript:;" onclick="">'.$page['title'].'</a>'; 

       //Set the page as the new parent 
       $newParent = $page['id']; 

       //Remove page from array 
       unset($subpages[$key]); 

       //Check the rest of the array for children 
       subPages($subpages, $newParent); 

       echo '</li>'; 
      } 
     } 
    } 
?> 

与往常一样,任何援助表示赞赏。请让我知道,如果有什么不明确的。

+0

听起来好像你正在描述一棵树的[深度优先搜索](http://en.wikipedia.org/wiki/Depth-first_search)。或者['heapsort'](http://en.wikipedia.org/wiki/Heapsort)。 – Matt 2012-08-16 15:28:04

+0

重构树或使用队列处理迭代,并且只有在队列中已经存在或处理完毕的列表中才添加到队列中。 – Waygood 2012-08-16 15:31:17

+0

所以没有优雅的方式来遍历和吐出数据? – dbergunder 2012-08-16 20:54:37

回答

2

我怀疑你们是否还在寻找真正的答案,但它可能会帮助其他人解决同样的问题。下面是一个递归函数,可以将一个数组放在父母的下方。

$initial = array(
    array(
     'name' => 'People', 
     'ID' => 2, 
     'parent' => 0 
     ), 
    array(
     'name' => 'Paul', 
     'ID' => 4, 
     'parent' => 2 
     ), 
    array(
     'name' => 'Liz', 
     'ID' => 5, 
     'parent' => 2 
     ), 
    array(
     'name' => 'Comus', 
     'ID' => 6, 
     'parent' => 3 
     ), 
    array(
     'name' => 'Mai', 
     'ID' => 7, 
     'parent' => 2 
     ), 
    array(
     'name' => 'Titus', 
     'ID' => 8, 
     'parent' => 3 
     ), 
    array(
     'name' => 'Adult', 
     'ID' => 9, 
     'parent' => 6 
     ), 
    array(
     'name' => 'Puppy', 
     'ID' => 10, 
     'parent' => 8 
     ), 
    array(
     'name' => 'Programmers', 
     'ID' => 11, 
     'parent' => 4 
     ) , 
    array(
     'name' => 'Animals', 
     'ID' => 3, 
     'parent' => 0 
     )       
    ); 


/*--------------------------------- 
function parentChildSort_r 
$idField  = The item's ID identifier (required) 
$parentField = The item's parent identifier (required) 
$els   = The array (required) 
$parentID  = The parent ID for which to sort (internal) 
$result  = The result set (internal) 
$depth   = The depth (internal) 
----------------------------------*/ 

function parentChildSort_r($idField, $parentField, $els, $parentID = 0, &$result = array(), &$depth = 0){ 
    foreach ($els as $key => $value): 
     if ($value[$parentField] == $parentID){ 
      $value['depth'] = $depth; 
      array_push($result, $value); 
      unset($els[$key]); 
      $oldParent = $parentID; 
      $parentID = $value[$idField]; 
      $depth++; 
      parentChildSort_r($idField,$parentField, $els, $parentID, $result, $depth); 
      $parentID = $oldParent; 
      $depth--; 
     } 
    endforeach; 
    return $result; 
} 

$result = parentChildSort_r('ID','parent',$initial); 

print '<pre>'; 
print_r($result); 
print '</pre>'; 

这是一个放松下来的方法,可以消除原来的数组元素,并将它们放入结果以适当的顺序设置。我对它有点泛泛,所以它只是需要你告诉它你的'ID'字段和'父'字段被调用。顶级项目需要具有0的parent_id(但是您的名称)。我还为每个项目添加深度标记,以便您可以在输出上设置格式。

0

我会尽力帮助你。

有可能在一个通撰写这样的关系:

/** 
    * Used for "recursive" folding of layout items 
    * Algorithm of infinite tree (non recursive method) 
    * 
    * @param array $items 
    * @return array 
    */ 
    function _foldItems($items) { 

     $result = array(); 

     foreach ($items as $key => $item) { 

      $itemName = $item['name']; 

      if (!isset($item['parent'])) 
       continue; 
      else { 

       $parentName = $item['parent']; // it can be either `name` or some `id` of the parent item 

       if (isset($result[$itemName][$item['sequence']])) { 

        // Done to eliminate `Warning: Cannot use a scalar value as an array in atLeisure_PropertyImport.class.php` 
        // Sometimes elements already in the list and have [name] => $count and next line tries to put item in array (item becomes parent) 
        if ( isset($result[$parentName][$item['parentSequence']]['items'][$itemName]) AND 
          is_scalar($result[$parentName][$item['parentSequence']]['items'][$itemName]) 
         ) 
         $result[$parentName][$item['parentSequence']]['items'][$itemName] = array(); 

        $result[$parentName][$item['parentSequence']]['items'][$itemName][$item['sequence']] = $result[$itemName][$item['sequence']]; 

        unset($result[$itemName][$item['sequence']]); 
       } else 
        $result[$parentName][$item['parentSequence']]['items'][$itemName] = $item['count']; 

       unset($items[$key]); 

       } // if // 

      if (empty($result[$itemName])) 
       unset($result[$itemName]); 

     } // foreach // 

     foreach ($items as $item) { // enumerating rest of the items (single items) 
      $itemName = $item['itemName']; 

      if (!isset($result[$itemName])) 
       $result[$itemName][$item['sequence']] = $item['count']; 
     } 

     return $result; 

    } 

例子可能有点难以阅读和理解的,因为真的是有太多的代码,但是我做了这个功能并非如此很久以前只有一个项目,它似乎是成功的工作。

注意:它也将工作,如果有多个相同的项目链接到一个父项目。它使用项目序号来避免将相似值混叠为一。