3 回答
TA贡献1856条经验 获得超17个赞
$tree = array( 'H' => 'G', 'F' => 'G', 'G' => 'D', 'E' => 'D', 'A' => 'E', 'B' => 'C', 'C' => 'E', 'D' => null);
function parseTree($tree, $root = null) { $return = array(); # Traverse the tree and search for direct children of the root foreach($tree as $child => $parent) { # A direct child is found if($parent == $root) { # Remove item from tree (we don't need to traverse this again) unset($tree[$child]); # Append the child into result array and parse its children $return[] = array( 'name' => $child, 'children' => parseTree($tree, $child) ); } } return empty($return) ? null : $return; }
function printTree($tree) { if(!is_null($tree) && count($tree) > 0) { echo '<ul>'; foreach($tree as $node) { echo '<li>'.$node['name']; printTree($node['children']); echo '</li>'; } echo '</ul>'; }}
$result = parseTree($tree);printTree($result);
$result
:
Array( [0] => Array( [name] => D [children] => Array( [0] => Array( [name] => G [children] => Array( [0] => Array( [name] => H [children] => NULL ) [1] => Array( [name] => F [children] => NULL ) ) ) [1] => Array( [name] => E [children] => Array( [0] => Array( [name] => A [children] => NULL ) [1] => Array( [name] => C [children] => Array( [0] => Array( [name] => B [children] => NULL ) ) ) ) ) ) ))
function parseAndPrintTree($root, $tree) { $return = array(); if(!is_null($tree) && count($tree) > 0) { echo '<ul>'; foreach($tree as $child => $parent) { if($parent == $root) { unset($tree[$child]); echo '<li>'.$child; parseAndPrintTree($child, $tree); echo '</li>'; } } echo '</ul>'; }}
TA贡献1811条经验 获得超5个赞
$array = array('H' => 'G', 'F' => 'G', ..., 'D' => null);function to_tree($array){ $flat = array(); $tree = array(); foreach ($array as $child => $parent) { if (!isset($flat[$child])) { $flat[$child] = array(); } if (!empty($parent)) { $flat[$parent][$child] =& $flat[$child]; } else { $tree[$child] =& $flat[$child]; } } return $tree;}
Array( [D] => Array( [G] => Array( [H] => Array() [F] => Array() ) ... ))
TA贡献1111条经验 获得超0个赞
$tree
// add children to parents$flat = array(); # temporary arrayforeach ($tree as $name => $parent){ $flat[$name]['name'] = $name; # self if (NULL === $parent) { # no parent, is root element, assign it to $tree $tree = &$flat[$name]; } else { # has parent, add self as child $flat[$parent]['children'][] = &$flat[$name]; }}unset($flat);
Array( [children] => Array ( [0] => Array ( [children] => Array ( [0] => Array ( [name] => H ) [1] => Array ( [name] => F ) ) [name] => G ) [1] => Array ( [name] => E [children] => Array ( [0] => Array ( [name] => A ) [1] => Array ( [children] => Array ( [0] => Array ( [name] => B ) ) [name] => C ) ) ) ) [name] => D)
RecursiveIteratorIterator
getDepth()
Iterator
<ul>
<ul>
<li>
TreeNode
-将每个元素抽象成一个简单的 TreeNode
可以提供它的值的类型(例如: Name
)以及它是否有孩子。 TreeNodesIterator
-A RecursiveIterator
可以迭代其中的一组(数组) TreeNodes
..这相当简单,因为 TreeNode
类型已经知道它是否有孩子和哪个孩子。 RecursiveListIterator
-A RecursiveIteratorIterator
当它递归地遍历任何类型的 RecursiveIterator
:beginIteration
/endIteration
-主名单的开始和结束。 beginElement
/endElement
-每个要素的开始和结束。 beginChildren
/endChildren
-每个儿童名单的开始和结束。这,这个 RecursiveListIterator
仅以函数调用的形式提供这些事件。子列表,这是典型的 <ul><li>
列表,在它的父级内部被打开和关闭 <li>
元素。因此 endElement
事件之后触发 endChildren
事件。可以对此进行更改或配置,以扩大该类的使用范围。事件以函数调用的形式分发给装饰器对象,以便将事情分开。 ListDecorator
-一个“装潢师”类,它仅仅是事件的接收者。 RecursiveListIterator
.
$tree
$root = new TreeNode($tree);$it = new TreeNodesIterator(array($root));$rit = new RecursiveListIterator($it);$decor = new ListDecorator($rit);$rit->addDecorator($decor);foreach($rit as $item){ $inset = $decor->inset(1); printf("%s%s\n", $inset, $item->getName());}
ListDecorator
<ul>
<li>
class ListDecorator{ private $iterator; public function __construct(RecursiveListIterator $iterator) { $this->iterator = $iterator; } public function inset($add = 0) { return str_repeat(' ', $this->iterator->getDepth()*2+$add); }
inset
public function beginElement() { printf("%s<li>\n", $this->inset()); } public function endElement() { printf("%s</li>\n", $this->inset()); } public function beginChildren() { printf("%s<ul>\n", $this->inset(-1)); } public function endChildren() { printf("%s</ul>\n", $this->inset(-1)); } public function beginIteration() { printf("%s<ul>\n", $this->inset()); } public function endIteration() { printf("%s</ul>\n", $this->inset()); }}
$root = new TreeNode($tree);
TreeNode
$it = new TreeNodesIterator(array($root));
TreeNodesIterator
RecursiveIterator
$root
TreeNode
$rit = new RecursiveListIterator($it);
RecursiveListIterator
RecursiveIteratorIterator
ListDecorator
addDecorator
:
$decor = new ListDecorator($rit);$rit->addDecorator($decor);
foreach
foreach($rit as $item){ $inset = $decor->inset(1); printf("%s%s\n", $inset, $item->getName());}
ListDecorator
foreach
ListDecorator
TreeNode
.
<?phpnamespace My;$tree = array('H' => 'G', 'F' => 'G', 'G' => 'D', 'E' => 'D', 'A' => 'E', 'B' => 'C', 'C' => 'E', 'D' => null);// add children to parents$flat = array(); # temporary arrayforeach ($tree as $name => $parent){ $flat[$name]['name'] = $name; # self if (NULL === $parent) { # no parent, is root element, assign it to $tree $tree = &$flat[$name]; } else { # has parent, add self as child $flat[$parent]['children'][] = &$flat[$name]; }}unset($flat);class TreeNode{ protected $data; public function __construct(array $element) { if (!isset($element['name'])) throw new InvalidArgumentException('Element has no name.'); if (isset($element['children']) && !is_array($element['children'])) throw new InvalidArgumentException('Element has invalid children.'); $this->data = $element; } public function getName() { return $this->data['name']; } public function hasChildren() { return isset($this->data['children']) && count($this->data['children']); } /** * @return array of child TreeNode elements */ public function getChildren() { $children = $this->hasChildren() ? $this->data['children'] : array(); $class = get_called_class(); foreach($children as &$element) { $element = new $class($element); } unset($element); return $children; }}class TreeNodesIterator implements \RecursiveIterator{ private $nodes; public function __construct(array $nodes) { $this->nodes = new \ArrayIterator($nodes); } public function getInnerIterator() { return $this->nodes; } public function getChildren() { return new TreeNodesIterator($this->nodes->current()->getChildren()); } public function hasChildren() { return $this->nodes->current()->hasChildren(); } public function rewind() { $this->nodes->rewind(); } public function valid() { return $this->nodes->valid(); } public function current() { return $this->nodes->current(); } public function key() { return $this->nodes->key(); } public function next() { return $this->nodes->next(); }}class RecursiveListIterator extends \RecursiveIteratorIterator{ private $elements; /** * @var ListDecorator */ private $decorator; public function addDecorator(ListDecorator $decorator) { $this->decorator = $decorator; } public function __construct($iterator, $mode = \RecursiveIteratorIterator::SELF_FIRST, $flags = 0) { parent::__construct($iterator, $mode, $flags); } private function event($name) { // event debug code: printf("--- %'.-20s --- (Depth: %d, Element: %d)\n", $name, $this->getDepth(), @$this->elements[$this->getDepth()]); $callback = array($this->decorator, $name); is_callable($callback) && call_user_func($callback); } public function beginElement() { $this->event('beginElement'); } public function beginChildren() { $this->event('beginChildren'); } public function endChildren() { $this->testEndElement(); $this->event('endChildren'); } private function testEndElement($depthOffset = 0) { $depth = $this->getDepth() + $depthOffset; isset($this->elements[$depth]) || $this->elements[$depth] = 0; $this->elements[$depth] && $this->event('endElement'); } public function nextElement() { $this->testEndElement(); $this->event('{nextElement}'); $this->event('beginElement'); $this->elements[$this->getDepth()] = 1; } public function beginIteration() { $this->event('beginIteration'); } public function endIteration() { $this->testEndElement(); $this->event('endIteration'); }}class ListDecorator{ private $iterator; public function __construct(RecursiveListIterator $iterator) { $this->iterator = $iterator; } public function inset($add = 0) { return str_repeat(' ', $this->iterator->getDepth()*2+$add); } public function beginElement() { printf("%s<li>\n", $this->inset(1)); } public function endElement() { printf("%s</li>\n", $this->inset(1)); } public function beginChildren() { printf("%s<ul>\n", $this->inset()); } public function endChildren() { printf("%s</ul>\n", $this->inset()); } public function beginIteration() { printf("%s<ul>\n", $this->inset()); } public function endIteration() { printf("%s</ul>\n", $this->inset()); }}$root = new TreeNode($tree);$it = new TreeNodesIterator(array($root));$rit = new RecursiveListIterator($it);$decor = new ListDecorator($rit);$rit->addDecorator($decor);foreach($rit as $item){ $inset = $decor->inset(2); printf("%s%s\n", $inset, $item->getName());}
<ul> <li> D <ul> <li> G <ul> <li> H </li> <li> F </li> </ul> </li> <li> E <ul> </li> <li> A </li> <li> C <ul> <li> B </li> </ul> </li> </ul> </li> </ul> </li></ul>
RecursiveIterator
- 3 回答
- 0 关注
- 739 浏览
添加回答
举报