您好我正在尝试打印类别和他们的孩子像db的树路径。直到现在我能够打印如下所示的树形结构数组。
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',
);
答案 0 :(得分:2)
这是一个多路树'。
更新:这是代码TreePaths
的完整重做
Original full source code at Pastebin.com - Execute at sandbox.onlinephpfunctions.com
这个答案描述了新代码。
变化:
输入array node
现在只需要children
条目而不是' leafs`。这使得输入更加一致。
此代码检查的array node
中唯一的条目是$node['children]
。这允许您在节点中拥有任何其他数据,您可以以callable
以任何方式处理它。
节点处理可以由具有以下符号的任何callable
替换:
function(array $currentPath, /* boolean */ $isTopALeaf) {...
如果nodeProcessor
(可调用)返回非空值,则它将被添加到$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 ...
答案 1 :(得分:0)
$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.
我希望这会对你有所帮助。
答案 2 :(得分:0)
基于此处设置的数据:https://pastebin.com/CGPniY8C 我是通过这种解决方案来解决的:
class Controller():
if getattr(sys, 'frozen', False):
path = os.path.dirname(sys.executable)
elif __file__:
path = os.path.dirname(__file__)
else:
print('No path has been defined')
windowWidth = 800
windowHeight = 600
def __init__(self):
self._running = True
self.sprites = pygame.sprite.Group()
self.callback = None
def on_init(self):
pygame.init()
pygame.display.set_caption('Ourstory')
self.clock = pygame.time.Clock()
self.screen = pygame.display.set_mode((self.windowWidth, self.windowHeight))
self.menu('MainMenu')
self._running = True
def on_event(self, event):
if event.type == QUIT:
self._running = False
elif event.type == TURN:
self.turn += 1
def on_loop(self):
pass
def on_cleanup(self):
pygame.quit()
def on_execute(self):
if self.on_init() == False:
self._running = False
while (self._running):
self.clock.tick(60)
pygame.event.pump()
#self.update_button()
#self.sprites._update_image(events)
self.screen.fill(pygame.Color('white'))
self.sprites.draw(self.screen)
pygame.display.update()
keys = pygame.key.get_pressed()
if (keys[K_ESCAPE]):
self._running = False
self.on_loop()
self.on_cleanup()
def menu(self, name:str):
if name == 'MainMenu':
background = Image._create_image(self, 'TOC_EarthDawn800600.png', 0, 0)
self.sprites.add(background)
#self.sprites.add(Controller.load_image(self, 'TOC_EarthDawn800600.png', 0, 0))
##Controller.load_button(self, 'SelectCivilisation', 'Culture3232.png', 'Espionage3232.png', 32, 32, 32, 32, -1, 'Select Civilisation', 'freesansbold.ttf', 8, (0,0,0))
#self.sprites.add(Button('TestButton', (128,128,128), (160,160,160), (0,0,0), pygame.Rect(150, 200, 90, 100), QUIT))#, 'text', 'freesansbold.ttf', 8, (0,0,0)))
elif name == 'NewGame':
Controller.load_image(self, 'TOC_EarthDusk800600.png', 0, 0)
else:
print('Cannot find menu: ', name)
class Image(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
def _create_image(self, name, x, y, colorkey=None):
self.name = name
fullname = os.path.join('Images', name)
try:
image = pygame.image.load(fullname)
except:
pygame.error
print('Cannot find image: ', name)
image = image.convert()
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0, 0)) # i.e. top-left pixel
image.set_colorkey(colorkey, RLEACCEL)
return image
class Button(pygame.sprite.Sprite):
def __init__(self, name:str, colourinactive:str, colouractive:str, colouroutline:str, rect, callback, text=None, font='freesansbold.ttf', fontsize=8, textcolour=(0,0,0), imageinactive=None, imageactive=None, colorkey=None):
super().__init__()
self.text = text
temprect = pygame.Rect(0, 0, *rect.size)
if not imageinactive:
self.inactive = self._create_image(colourinactive, colouroutline, temprect, text)
self.active = self._create_image(colouractive, colouroutline, temprect, text)
self.image = self.inactive
self.rect = rect
self.callback = callback
def _create_image(self, colourinactive:str, colouroutline:str, rect, text=None, font='freesansbold.ttf', fontsize=8, textcolour=(0,0,0)):
imagesurface = pygame.Surface(rect.size)
if colouroutline:
imagesurface.fill(colouroutline)
imagesurface.fill(colourinactive, rect.inflate(-4, -4))
else:
imagesurface.fill(colourinactive)
if text:
font = pygame.font.Font(font, fontsize)
print(type(textcolour))
textsurface = font.render(text, True, pygame.Color(textcolour))
textrect = textsurface.get_rect(center=rect.center)
img.blit(textsurface, textrect)
return imagesurface
def _update_image(self, events):
mouse = pygame.mouse.get_pos()
active = self.rect.collidepoint(mouse)
self.image = self.active if active else self.inactive
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN and hit:
self.callback(self)
输出:
/* Initialize dataset */
$srcTree = Array(...dataset_pastebin...);
/*
$children = List of children
$node_path = Original node path
$node_path_storage = Array to store all path found
*/
function getPathFromTree($children, $node_path, &$node_path_storage){
$original_node_path = $node_path;
foreach ($children as $child){
$node_path = $original_node_path . '/' . $child['Slug'];
array_push($node_path_storage, $node_path);
if(!empty($child['children'])){
getPathFromTree($child['children'], $node_path, $node_path_storage);
}
}
}
/* Usage */
$node_path_storage = array();
getPathFromTree($srcTree, '', $node_path_storage);
echo '<pre>' . print_r($node_path_storage, true) . '</pre>';