Привет, я пытаюсь напечатать категории и их детей, как дерево путей из БД. До сих пор я могу распечатать древовидный массив, как показано ниже.
Array
(
[0] => Array
(
[name] => 'Furniture'
[slug] => 'furniture'
[children] => Array
(
[0] => Array
(
[name] => 'Sofa'
[slug] => 'sofa'
[leafs] => Array
(
[0] => Array ( [name] => '3 Seater', [slug] = '3-seater'
[1] => Array ( [name] => '4 Seater', [slug] = '4-seater'
)
)
[1] => Array
(
[name] => 'Chairs'
[slug] => 'chairs'
[leafs] => Array
(
[0] => Array ( [name] => '3 Seater', [slug] = '3-seater'
[1] => Array ( [name] => '4 Seater', [slug] = '4-seater'
)
)
)
)
[1] => Array
(
[name] => 'Furniture1'
[slug] => 'furniture1'
[children] => Array
(
[0] => Array
(
[name] => 'Sofa1'
[slug] => 'sofa1'
[leafs] => Array
(
[0] => Array ( [name] => '3 Seater1', [slug] = '3-seater1'
[1] => Array ( [name] => '4 Seater1', [slug] = '4-seater1'
)
)
[1] => Array
(
[name] => 'Chairs1'
[slug] => 'chairs1'
[leafs] => Array
(
[0] => Array ( [name] => '3 Seater1', [slug] = '3-seater1'
[1] => Array ( [name] => '4 Seater1', [slug] = '4-seater1'
)
)
)
)
)
У некоторых детей могут быть листья или у некоторых родителей могут быть дети. Но то, что я пытаюсь напечатать, было похоже ниже.
Array(
[0] => 'Furniture/Sofa/3 Seater',
[1] => 'Furniture/Sofa/4 Seater',
[2] => 'Furniture/Chiars/ 3 Seater'
[3] => 'Furniture/Chiars/4 Seater',
[4] => 'Furniture1/Sofa1/3 Seater1',
[5] => 'Furniture1/Sofa/4 Seater1',
[6] => 'Furniture1/Chiars1/ 3 Seater1'
[7] => 'Furniture1/Chiars1/4 Seater1',
);
Это «многоходовое дерево».
Обновить: Это полная переделка кода как класса TreePaths
Оригинальный полный исходный код на Pastebin.com — Выполнить на sandbox.onlinephpfunctions.com
Этот ответ описывает новый код.
Перемены:
Вход array node
теперь нужно только children
запись, а не «листья». Это делает ввод более последовательным.
Единственная запись в array node
проверено этим кодом $node['children]
, Это позволяет вам иметь любые другие данные в узле, которые вы хотите, и вы можете обрабатывать их в callable
любым способом, который вы пожелаете.
Обработка узла может быть заменена любым callable
имеющий подпись:
function(array $currentPath, /* boolean */ $isTopALeaf) {...
Если nodeProcessor
(callable) возвращает значение, которое не является пустым, тогда оно будет добавлено к $allPaths
массив.
Веб-сайт:
Интересно то, что мы должны хранить «путь» к «конечным» узлам.
«Путь» кажется «особенным». Однако, представьте, что каждый раз, когда вы «рекурсируете» или «вкладываете» вниз на один уровень, вы записываете, где находитесь в «стеке».
Когда вы достигнете конца текущего списка, вы:
nodeProcessor
Я использую «древовидную структуру» и имена, как указано.
В конце каждого пути nodeProcessor
называется с the current path
Выходы:
Поскольку это дерево, то требуется «рекурсивный» алгоритм, поскольку «глубина» дерева неизвестна.
Программа должна:
/*
* Generate an HTML anchor tag from the 'slug' entries
*/
$slugNodeProcessor =
function(array $currentPath,
$isTopALeaf) {
/*
* Lets make some HTML anchors for the Slugs?
*/
$template = '<a href="%s" class="Slug">%s</a>';
// top of the stack will be a leaf
$title = '';
$top = end($currentPath); // easier to work with
$prev = prev($currentPath); // need the description for title
$title = $prev['name'] .' - '. $top['name'];
$url = '/';
foreach($currentPath as $key => $node) {
$url .= $node['Slug'] .'/';
};
$url = rtrim($url, '/');
$htmlSlug = sprintf($template, $url, $title);
return $htmlSlug;
};
/**
* If you don't provide a callable to generate paths then this will be used.
*
* It generates a string of names separated by '/'. i.e. it looks like a filepath.
*
* @return string
*/
public function defaultNodeProcessor()
{
$dnp = function(array $currentPath,
$isTopALeaf) {
$fullPath = '/';
foreach($currentPath as $key => $node) {
$fullPath .= $node['name'] .'/';
}
return rtrim($fullPath, '/');
};
return $dnp;
}
$tree = new TreePaths($srcTree,
$slugNodeProcessor);
$tree->generate();
$allPaths = $tree->allPaths();
array (8) [
string (67) "<a href="/furniture/sofa/3-seater" class="Slug">Sofa - 3 Seater</a>"string (67) "<a href="/furniture/sofa/4-seater" class="Slug">Sofa - 4 Seater</a>"string (76) "<a href="/furniture/sofa/chairs/3-seater" class="Slug">Chairs - 3 Seater</a>"string (76) "<a href="/furniture/sofa/chairs/4-seater" class="Slug">Chairs - 4 Seater</a>"string (94) "<a href="/furniture/sofa/chairs/furniture1/sofa1/3-seater1" class="Slug">Sofa1 - 3 Seater1</a>"string (94) "<a href="/furniture/sofa/chairs/furniture1/sofa1/4-seater1" class="Slug">Sofa1 - 4 Seater1</a>"string (104) "<a href="/furniture/sofa/chairs/furniture1/sofa1/chairs1/3-seater1" class="Slug">Chairs1 - 3 Seater1</a>"string (104) "<a href="/furniture/sofa/chairs/furniture1/sofa1/chairs1/4-seater1" class="Slug">Chairs1 - 4 Seater1</a>"]
/*
* Source Tree:
*
* Tree Node:
*
* Array(
* "name" => 'Furniture', // not checked
* "slug" => 'furniture', // optional - not used
* "children" => Array( // will be other Tree nodes...
* ),
* );
*
* The `children` key is optional, if empty or missing, means it is a `leaf` node
*
* !!! Note: The only array entry checked in here is 'children' !!!
*
* But you will need to overide the default nodeProcessor.
*
* The default `nodeProcessor` uses `name` and `children` only
*/
/*
* NodeProcessor:
* o It is a callable that accepts two parameters
* o current path - an array of all the nodes so far in this path
* o isTopALeaf - is the end of the path a 'leaf' node?
*/
/**
* Traverse the tree of `nodes`
* Generate a list of Paths from Root to every leaf node as an array of `nodes`.
* It is a `stack` with the top node being a leaf.
*/
class TreePaths {
/**
* The 'current' menu / tree
*
* @var array $tree
*/
private $tree = array();
/**
* The Output
*
* @var array $allPaths
*/
private $allPaths = array();
/**
* The 'current' stack of nodes in this path
*
* This is a 'stack'. The 'path' is all the entries combined.
*
* @var array $currentPath
*/
private $currentPath = array();
/**
* The 'callable' to be run for nodes
*
* @var callable $nodeProcessor
*/
private $nodeProcessor = null;
/**
* Call All Nodes or Leaf node only
*
* @var boolean
*/
private $callLeafNodesOnly = true;
/**
* Build the class but do not run it...
*
* Provides a default NodeProcessor if you don't provide one.
* o The default processor builds string paths that look like filepaths
*
* @param array $tree
* @param callable $processNode - optional
* @param boolean $callLeafNodesOnly - optional default true
*/
public function __construct(array $tree,
/* callable */ $processNode = null,
$callLeafNodesOnly = true)
{
$this->tree = $tree;
$this->nodeProcessor = $processNode;
$this->callLeafNodesOnly = $callLeafNodesOnly;
// provide a default processor
if (is_null($this->nodeProcessor)) {
$this->nodeProcessor = $this->defaultNodeProcessor();
}
}
/**
* This routine makes this class rather powerful as you can use any callable.
*
* @param type $nodeProcessor
*/
public function setNodeProcessor(/* callable */ $nodeProcessor)
{
$this->nodeProcessor = $nodeProcessor;
}
/**
* Return a list of all the paths that were generated by the 'nodeProcessor'
* @return array
*/
public function allPaths()
{
return $this->allPaths;
}
/**
* The routine that processes one node and recurses as required
*
* @param array $node
* @return void This is all side-effects
*/
protected function treeWalk($node)
{
// always add the node to the currentPath
array_push($this->currentPath, $node);
// Always call the node processor and add the path to all paths if required
$processedPath = $this->callNodeProcessor($this->currentPath,
$this->isLeafNode($node));
if (!empty($processedPath)) { // add to all the paths
$this->allPaths[] = $processedPath;
}
// do we recurse?
if ($this->isLeafNode($node)) { // no we dont...
array_pop($this->currentPath); // lose leaf node from top of stack
return; // nothing more to do
}
// now process all the children... This will recurse - always
foreach ($node['children'] as $key => $node) {
$this->treeWalk($node);
}
return; // end of children
}
/**
* Process all the top level nodes.
*
* @return void
*/
public function generate()
{
$this->allPaths = array();
foreach ($this->tree as $key => $node) {
$this->treeWalk($node);
}
return;
}
/**
* End of a path?
*
* @param array $node
* @return boolean
*/
protected function isLeafNode($node)
{
return empty($node['children']);
}
/**
* Are we in the 'middle' of a path?
*
* @param array $node
* @return boolean
*/
protected function hasChildren($node)
{
return !empty($node['children']);
}
/**
* The `callable` to be called.
*
* It must accept the two parameters.
*
* It can be set after the 'class instance' is created.
*
* @param array currentPath to this value
* @param string nodeType - leaf or children
*
* @return mixed if not empty will be added to the paths
*/
protected function callNodeProcessor(array $currentPath,
$isTopALeaf)
{
if ($this->callLeafNodesOnly) {
if ($isTopALeaf) {
return call_user_func($this->nodeProcessor,
$currentPath,
$isTopALeaf);
}
}
else {
return call_user_func($this->nodeProcessor,
$currentPath,
$isTopALeaf);
}
}
/**
* If you don't provide a callable to generate paths then this will be used.
*
* It generates a string of names separated by '/'. i.e. it looks like a filepath.
*
* @return string
*/
public function defaultNodeProcessor()
{
$dnp = function(array $currentPath,
$isTopALeaf) {
$fullPath = '/';
foreach($currentPath as $key => $node) {
$fullPath .= $node['name'] .'/';
}
return rtrim($fullPath, '/');
};
return $dnp;
}
}
/*
* Tree Node:
*
* Array(
* "name" => 'Furniture',
* "slug" => 'furniture',
* "children" => Array( // can be other Tree nodes...
* ),
* );
*
* The `children` key is optional, if empty or missing, means it is a `leaf` node
*
* !!! Note: The only array entry checked in here is 'children' !!!
*
* But you would need to overide the default nodeProcessor.
*/
$srcTree = Array(
0 => Array(
"name" => 'Furniture',
"Slug" => 'furniture',
"children" => Array(
"0" => Array
(
"name" => 'Sofa',
"Slug" => 'sofa',
"children" => Array
(
"0" => Array ( "name" => '3 Seater', "Slug" => '3-seater'),
"1" => Array ( "name" => '4 Seater', "Slug" => '4-seater'),
),
),
"1" => Array
(
"name" => 'Chairs',
"Slug" => 'chairs',
"children" => Array
(
"0" => Array ( "name" => '3 Seater', "Slug" => '3-seater'),
"1" => Array ( "name" => '4 Seater', "Slug" => '4-seater'),
)
)
)
),
More entries here ...
$fullname = array();
$mainarrs = array(); //this is the array that will have your all the array data
$i=0;
foreach ( $mainarrs as $mainarr )
{
$temp = $mainarr['name'];
foreach($mainarr as $anmain)
{
$temp2 = $anmain['name'];
foreach($anmain as $lastmain)
{
$fullname[$i] = $temp."/".$temp2."/".$lastmain['name']
}
}
}
//now for the output that you expect to see is in $fullname array, you can loop through it to see the result.
Я надеюсь, это поможет вам.