2012-01-12 27 views
24

Tôi đã xem xét trên Internet và không tìm thấy những gì tôi đang tìm kiếm. Tôi có một mảng phẳng với mỗi phần tử chứa 'id' và 'parent_id'. Mỗi phần tử sẽ chỉ có MỘT phụ huynh, nhưng có thể có nhiều trẻ em. Nếu parent_id = 0, nó được coi là một mục cấp độ gốc. Tôi đang cố gắng để có được mảng phẳng của tôi vào một cái cây. Các mẫu khác tôi đã tìm thấy chỉ sao chép phần tử vào phần tử gốc, nhưng bản gốc vẫn tồn tại.Tạo một cây từ một mảng phẳng trong PHP

EDIT

Mỗi phần tử của mảng bắt đầu được đọc từ một tập tin XML riêng biệt. Bản thân tệp sẽ có '0' làm giá trị cho parent_id nếu nó không có cha mẹ. Các phím thực sự là dây.

Tôi xin lỗi vì sự nhầm lẫn trước đó. Hy vọng rằng đây là rõ ràng hơn:

/EDIT

mảng khởi đầu của tôi:

 
Array 
(
    [_319_] => Array 
     (
      [id] => 0 
      [parent_id] => 0 
     ) 

    [_320_] => Array 
     (
      [id] => _320_ 
      [parent_id] => 0 
     ) 

    [_321_] => Array 
     (
      [id] => _321_ 
      [parent_id] => _320_ 
     ) 

    [_322_] => Array 
     (
      [id] => _322_ 
      [parent_id] => _321_ 
     ) 

    [_323_] => Array 
     (
      [id] => _323_ 
      [parent_id] => 0 
     ) 

    [_324_] => Array 
     (
      [id] => _324_ 
      [parent_id] => _323_ 
     ) 

    [_325_] => Array 
     (
      [id] => _325_ 
      [parent_id] => _320_ 
     ) 
)

Mảng kết quả sau khi cây được thực hiện:

 
Array 
(
    [_319_] => Array 
     (
      [id] => _319_ 
      [parent_id] => 0 
     ) 

    [_320_] => Array 
     (
      [id] => _320_ 
      [parent_id] => 0 
      [children] => Array 
       (
        [_321_] => Array 
         (
          [id] => _321_ 
          [parent_id] => _320_ 
          [children] => Array 
           (
            [_322_] => Array 
             (
              [id] => _322_ 
              [parent_id] => _321_ 
             ) 
           ) 
         ) 
        [_325_] => Array 
         (
          [id] => _325_ 
          [parent_id] => _320_ 
         ) 
       ) 
    [_323_] => Array 
     (
      [id] => _323_ 
      [parent_id] => 0 
      [children] => Array 
       (
        [_324_] => Array 
         (
          [id] => _324_ 
          [parent_id] => _323_ 
         ) 
       ) 
     ) 

Bất kỳ sự giúp đỡ/hướng dẫn là đánh giá cao!

Một số mã tôi có cho đến nay:

 

     function buildTree(array &$elements, $parentId = 0) { 
     $branch = array(); 

     foreach ($elements as $element) { 
      if ($element['parent_id'] == $parentId) { 
       $children = $this->buildTree($elements, $element['id']); 
       if ($children) { 
        $element['children'] = $children; 
       } 
       $branch[] = $element; 
      } 
     } 

     return $branch; 
    } 

+1

Tôi đang bối rối. Bạn chỉ yêu cầu chúng tôi viết mã mà có mảng nắm tay của bạn và phun ra những gì bạn có trong mảng thứ hai? – MetalFrog

+0

Vâng ... câu hỏi ở đây là gì? –

+0

Tóm lại, tôi đoán vậy. Tôi đã xem xét nhiều ví dụ khác ở đây về stackoverflow và trên các blog/diễn đàn khác. Nhưng khi tôi đã thử họ, họ không làm việc. – DSkinner

Trả lời

38

Bạn quên unset() trong đó bro.

function buildTree(array &$elements, $parentId = 0) { 
    $branch = array(); 

    foreach ($elements as $element) { 
     if ($element['parent_id'] == $parentId) { 
      $children = buildTree($elements, $element['id']); 
      if ($children) { 
       $element['children'] = $children; 
      } 
      $branch[$element['id']] = $element; 
      unset($elements[$element['id']]); 
     } 
    } 
    return $branch; 
} 
+3

Giải pháp này có thể không xây dựng đúng cây trong một số trường hợp nhất định (tức là$ arr = array (mảng ('id' => 1, 'parentid' => 0), mảng ('id' => 10, 'parentid' => 2), mảng ('id' => 2, 'parentid '=> 0), mảng (' id '=> 3,' parentid '=> 10), mảng (' id '=> 4,' parentid '=> 0), mảng (' id '=> 11,' parentid '=> 1), mảng (' id '=> 5,' parentid '=> 0), mảng (' id '=> 6,' parentid '=> 1), mảng (' id '=> 8, 'parentid' => 11), mảng ('id' => 9, 'parentid' => 0), mảng ('id' => 7, 'parentid' => 0),);) Tôi khuyên bạn nên: http://stackoverflow.com/questions/4196157/create-array-tree-from-array-list (giải pháp sửa đổi của Arthur) – danicotra

+1

Nó không cứu được cha mẹ đầu tiên không có con. – mrded

+0

@Freedom_Ben cảm ơn tôi đã thử :) – n0nag0n

3

tôi có thể thấy logic, tiết kiệm cho điều này trong kết quả:

Array 
(
    [0] => Array 
     (
      [id] => 0 
      [parent_id] => 0 
     ) 

    [1] => Array 
     (
      [id] => 1 
      [parent_id] => 0 
     ) 

IMHO, là PARENT_ID = o, không nên [1 ] là con của [0] ở đây?

Dù sao, tài liệu tham khảo để giải cứu:

$tree = array(); 
foreach($inputarray as $item){ 
    if(!isset($tree[$item['id']])) $tree[$item['id']] = array(); 
    $tree[$item['id']] = array_merge($tree[$item['id']],$item); 
    if(!isset($tree[$item['parent_id']])) $tree[$item['parent_id']] = array(); 
    if(!isset($tree[$item['parent_id']]['children'])) $tree[$item['parent_id']]['children'] = array(); 
    $tree[$item['parent_id']]['children'][] = &$tree[$item['id']]; 
} 
$result = $tree[0]['children']; 
unset($tree); 
print_r($result); 

Bởi vì bạn đã lạm dụng 0 như cả một 'ma thuật' số như là người chủ, và một id hiện có, bây giờ chúng tôi có đệ quy trong id = 0 chi nhánh. Thêm if($item['parent_id']!=$item['id']) trước $tree[$item['parent_id']]['children'][] = &$tree[$item['id']]; có thể ngăn chặn điều đó nhưng không đẹp.

+0

+1 vì việc truyền lại đã khiến kích thước bộ nhớ cho phép bị cạn kiệt trong trường hợp của tôi. Trong trường hợp của tôi có 54 đối tượng và điều này là đủ để hoàn thành trí nhớ của tôi. – bumerang

2

Có thể để xây dựng các mảng nguồn hơi khác nhau mà bạn có thể sử dụng chức năng này (PARENT_ID, id, title):

$q = mysql_query("SELECT id, parent_id, name FROM categories"); 
while ($r = mysql_fetch_row($q)) { 
    $names[$r[0]] = $r[2]; 
    $children[$r[0]][] = $r[1]; 
} 

function render_select($root=0, $level=-1) { 
    global $names, $children; 
    if ($root != 0) 
    echo '<option>' . strrep(' ', $level) . $names[$root] . '</option>'; 
    foreach ($children[$root] as $child) 
    render_select($child, $level+1); 
} 

echo '<select>'; 
render_select(); 
echo '</select>'; 
  1. More efficient hierarchy system
0

Bạn muốn được nhìn vào lưu trữ và tải dữ liệu phân cấp trong MySQL như tôi này nên giải quyết một vài vấn đề. Tôi giả định rằng mảng đầu tiên đại diện cho dữ liệu được lấy trực tiếp từ cơ sở dữ liệu?

Dường như bạn đang cố gắng sử dụng mô hình kề phụ để sắp xếp dữ liệu của bạn vào cấu trúc phân cấp. Ngoài ra còn có những cách khác để đạt được điều này bằng cách lồng ghép. Nếu bạn không lấy dữ liệu này từ một cơ sở dữ liệu thì điều này có thể không hữu ích.

Liên kết này sẽ giúp bạn ra ngoài: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

+0

Mặc dù nó minh họa chính xác việc sử dụng cả Mô hình Adjacency như Nested Set, trong thực tế (ít nhất, theo kinh nghiệm của tôi), Nested Set Model là waaaaay tốn kém về đột biến (trung bình một nửa bảng của bạn cần được cập nhật!) cho bất kỳ dữ liệu thực tế nào. Nếu dữ liệu tương đối cũ (ví dụ: hiếm khi thay đổi) thì có thể thực hiện được, nhưng thông thường, đây không phải là trường hợp. – Wrikken

+0

@Wrikken Vâng nó phụ thuộc vào cách dữ liệu đang được sử dụng/cập nhật. Đối với các danh mục thì tốt nhưng đối với dữ liệu có nhiều sửa đổi thì nó không thể thực hiện được. Quên đề cập đến điều đó, cảm ơn :) –

5

này làm việc cho tôi:

$index=array(); 
$tree=array(); 
foreach ($ori as $key=>$var) { 
    $var=array_shift($ori); 
    if ($var['id']==0) $var['id']=$key; 
    if ((string)$var['parent_id']==='0') { 
    $tree[$key]=$var; 
    $index[$key]=&$tree[$key]; 
    } else if (isset($index[$var['parent_id']])) { 
    if (!isset($index[$var['parent_id']]['children'])) $index[$var['parent_id']]['children']=array(); 
    $index[$var['parent_id']]['children'][$key]=$var; 
    $index[$key]=&$index[$var['parent_id']]['children'][$key]; 
    } else { 
    array_push($ori,$var); 
    } 
} 
unset($index); 
print_r($tree); 
+0

Tôi thích việc sử dụng chỉ mục. Rực rỡ. –

0

Đây là giải pháp của tôi, làm việc lý tưởng, nếu chúng ta giả định rằng mức độ PARENT_ID top = 0:

function MakeTree($arr){ 
    $parents_arr=array(); 
    foreach ($arr as $key => $value) { 
     $parents_arr[$value['pid']][$value['id']]=$value; 
    } 
    $tree=$parents_arr['0']; 
    $this->createTree($tree, $parents_arr); 
    return $tree; 
} 
function createTree(&$tree, $parents_arr){ 
    foreach ($tree as $key => $value) { 
     if(!isset($value['children'])) { 
      $tree[$key]['children']=array(); 
     } 
     if(array_key_exists($key, $parents_arr)){ 
      $tree[$key]['children']=$parents_arr[$key]; 
      $this->createTree($tree[$key]['children'], $parents_arr); 
     } 
    } 
} 
2

Mặc dù đây là một câu hỏi cũ, tôi sẽ bài trả lời của tôi ở đây:

/* assuming top level pid = 0 */ 
$rows = array (
    array ('id' => 1, 'pid' => 0), 
    /* ... */ 
); 

/* make id become array key */ 
$rows = array_column ($rows, null, 'id'); 

foreach ($rows as $key => $val) { 
    if ($val ['pid']) { 
     if (isset ($rows [$val ['pid']])) { 
      $rows [$val ['pid']]['children'][] = &$rows [$key]; 
     } 
    } 
} 

foreach ($rows as $key => $val) { 
    if ($val ['pid']) unset ($rows [$key]); 
} 

array_column là PHP 5,5 nhưng bạn có thể tự làm dễ dàng.

22

Giải pháp của ImmortalFirefly đang hoạt động, tuy nhiên, như đã chỉ ra, nó không lưu được cha mẹ đầu tiên không có con. Tôi đã chỉnh sửa chức năng để khắc phục vấn đề này:

function buildTree(array &$elements, $parentId = 0) { 

    $branch = array(); 

    foreach ($elements as &$element) { 

     if ($element['parent_id'] == $parentId) { 
      $children = buildTree($elements, $element['id']); 
      if ($children) { 
       $element['children'] = $children; 
      } 
      $branch[$element['id']] = $element; 
      unset($element); 
     } 
    } 
    return $branch; 
} 
+0

Bạn vừa lưu lại 6. Ông chủ của tôi sắp đánh tôi đến chết. Phew. Cám ơn nhiều, ông bạn. –

+0

Cảm ơn! Đúng thứ tôi cần! – maxpower9000

0

Đây là giải pháp, sao chép và tối ưu hóa các giải pháp khác của tôi.

function buildTree(array &$elements, $parentId = 0) { 
    $branch = array(); 
    foreach ($elements as $key => $element) { 
     if ($element['parent_id'] == $parentId) { 
      $children = $this->buildTree($elements, $key); 
      if ($children) { 
       $element['children'] = $children; 
      } 
      $branch[$key] = $element; 
      unset($elements[$key]); 
     } 
    } 
    return $branch; 
} 
0

Sạch sẽ, ngắn và không có chấn lưu. Mảng mảng đến cây:

class Mother { 
    private $root; 
    public function treeInit($array) 
    { 
     $this->root = new Child(); 
     foreach($array as $value){ 
      $this->root->treeClimb(array_reverse($value)); 
     } 
     return $this->root; 
    } 
} 

class Child { 
    private $children = []; 
    public function treeClimb($arr) 
    { 
     if(count($arr) > 0) { 
      $childTmp = array_pop($arr); 
      if(!key_exists($childTmp,$this->children)) 
      { 
       $this->children[$childTmp] = new Child(); 
      } 
     $this->children[$childTmp]->treeClimb($arr); 
     } 
    } 
} 

$array = array(array('obst','banae','krumm','gelb'), 
        array('obst','beere','him'), 
        array('obst','beere','brom'), 
        array('obst','banae','gerade'), 
        array('veg','carot','gerade')); 

$obj = new Mother(); 
var_dump($obj->treeInit($array)); 
Các vấn đề liên quan