2010-12-01 29 views
6

Tôi có một cây các loại có cấu trúc sau:Đệ quy và đi ngang qua tham khảo

[6] => Array 
    (
     [id] => 6 
     [name] => computers 
     [productCount] => 0 
     [children] => Array 
      (
       [91] => Array 
        (
         [id] => 91 
         [name] => notebook 
         [productCount] => 5 
         [children] => Array 
          (
          ) 
        ) 

       [86] => Array 
        (
         [id] => 86 
         [name] => desktop 
         [productCount] => 0 
         [children] => Array 
          (
          ) 
        ) 
      ) 
    ) 

Bên cạnh một tiểu thể loại, mỗi loại có thể chứa các sản phẩm (như một thư mục có thể chứa các thư mục con và chỉ tập tin).

Tôi đang cố gắng viết hàm đệ quy mà tôi muốn lấy mảng này làm tham chiếu và loại bỏ cả hai loại lá với [productCount] = 0 và tất cả các danh mục mẹ có chứa các nút trống như vậy. Nói cách khác, sau khi xử lý, tôi muốn chỉ có những danh mục giữ sản phẩm trên bất kỳ cấp phụ nào.

Tôi đã viết một số mã, hiện đang gỡ lỗi và nó không loại bỏ các nút trống. Có thể tôi không sử dụng tài liệu tham khảo đúng cách. Xin vui lòng, giúp tôi sửa chữa nó, nếu có thể.

function pruneTree(& $node) { 
    if (! $node['children'] && ! $node['productCount']) { 
     unset($node); 
    } 
    if (! empty($node['children'])) { 
     foreach ($node['children'] as $key => $child) { 
      pruneTree($node['children'][$key]); 
     } 
    } 
    return; 
} 
+0

Là 'mảng() == false'? – jantimon

+1

@Ghommey: Có, trong PHP một mảng trống được coi là giả. – BoltClock

Trả lời

4

Bạn cũng có thể thay đổi các tham số trong hàm để có một mảng các nút thay vì một nút duy nhất. Điều này thay đổi đệ quy một chút, và ngăn ngừa sự cần thiết phải vượt qua cùng một phím:

function pruneTree(&$nodes) { 
    foreach ($nodes as $key => $node) { 
     if (!$node['children'] && !$node['productCount']) { 
      unset($nodes[$key]); 
     } elseif (!empty($node['children'])) { 
      pruneTree($nodes[$key]['children']); 
      // This line checks if all the children have been pruned away: 
      if (empty($nodes[$key]['children'])) { 
       unset($nodes[$key]); 
      } 
     } 
    } 
} 

Ngoài ra, thêm một tấm séc để đảm bảo rằng nếu tất cả các nút con được cắt tỉa, phụ huynh (bây giờ, lá) nút cũng được cắt tỉa.

Hy vọng điều này sẽ hữu ích! dữ liệu


Test:

$data = array(
    6 => array(
     'id' => 6, 
     'name' => 'computers', 
     'productCount' => 0, 
     'children' => array(
      91 => array(
       'id' => 91, 
       'name' => 'notebook', 
       'productCount' => 5, 
       'children' => array() 
      ), 
      86 => array(
       'id' => 86, 
       'name' => 'desktop', 
       'productCount' => 0, 
       'children' => array() 
      ) 
     ) 
    ) 
); 

Call:

pruneTree($data); 
echo '<pre>'; 
print_r($data); 
echo '</pre>'; 
+0

Nó chỉ ra rằng không thể sử dụng 'unset ($ nodes [$ key]);' bên trong một hàm để sửa đổi mảng ban đầu được chuyển bởi tham chiếu, vì nó sẽ không đặt biến tham chiếu trong phạm vi hàm. – sevenWonders

+0

@sevenWonders - Tôi quên đề cập đến rằng tôi đã thử nghiệm kịch bản này (cũng như của Gumbo) và cả hai đều hoạt động. Có hầu như không có sự khác biệt, ngoại trừ việc tôi tìm thấy chìa khóa từ bên trong hàm được gọi trước khi unsetting. – RabidFire

+0

@RabidFire - Kỳ lạ khi tôi kiểm tra hàm của bạn, tôi nhận được lỗi "Chỉ các biến có thể được chuyển bằng tham chiếu" tại dòng 'pruneTree ($ nodes [$ key] [' children ']); '. – sevenWonders

5

unset xóa chỉ tham khảo nhưng không phải là biến tham chiếu:

Nếu một biến mà được thông qua tham khảo là unset() bên trong một hàm, chỉ có biến cục bộ bị phá hủy. Biến trong môi trường gọi sẽ giữ nguyên giá trị giống như trước khi gọi unset().

Vì vậy, bạn cần phải vượt qua các mảng phụ huynh và chìa khóa để xóa biến rằng:

function pruneTree(&$parent, $key) { 
    $node = &$parent[$key]; 
    if (!$node['children'] && !$node['productCount']) { 
     unset($parent[$key]); 
    } 
    if (!empty($node['children'])) { 
     foreach ($node['children'] as $key => &$child) { 
      pruneTree($node['children'], $key); 
     } 
    } 
} 
+0

Cảm ơn bạn, Gumbo! Tôi đã tìm kiếm manh mối trên trang "tài liệu tham khảo" của hướng dẫn sử dụng, và bỏ lỡ điểm với 'unset' và phạm vi. – sevenWonders

0

Tôi không biết nếu điều này là trường hợp, nhưng khi tôi cần phải thay đổi giá trị một cách đệ quy trong mảng , tôi cũng cần phải vượt qua & cho giá trị foreach.

private function convertXMLPart(&$array) { 
     foreach ($array as $rowKey => &$row) { 
      if (gettype($row) != 'string') { 
       $row = (array)$row; 
       if (!empty($row['@attributes'])) { 
        foreach ($row['@attributes'] as $key => $value) { 
         $row[$key] = $value; 
        } 
        unset($row['@attributes']); 
        $array[$rowKey] = $row; 
       } 
       $this->convertXMLPart($row); 
      } 
     } 
    } 
Các vấn đề liên quan