我有一个递归数据结构,如下面的例子,我希望它可以是每个分支的目标,从null(parentTagId)扩展到最后一个。
我不知道怎么做,任何建议都会受到赞赏!!
原始数据:
[
{ TagId: 2, ParentTagId: null, Name: 'women' },
{ TagId: 5, ParentTagId: 2, Name: 'bottom' },
{ TagId: 4, ParentTagId: 2, Name: 'top' },
{ TagId: 7, ParentTagId: 4, Name: 'shirt' },
{ TagId: 8, ParentTagId: 4, Name: 'tshirt' },
{ TagId: 12, ParentTagId: 7, Name: 'longsleeve' },
{ TagId: 16, ParentTagId: null, Name: 'men' }
]
预期结果:
women > bottom
women > top > shirt > longsleeve
women > tshirt
men
输出数据:
[
{
path: [
{ TagId: 2, ParentTagId: null, Name: 'women' },
{ TagId: 5, ParentTagId: 2, Name: 'bottom' }
]
},
{
path: [
{ TagId: 2, ParentTagId: null, Name: 'women' },
{ TagId: 4, ParentTagId: 2, Name: 'top' },
{ TagId: 7, ParentTagId: 4, Name: 'shirt' },
{ TagId: 12, ParentTagId: 7, Name: 'longsleeve' }
]
},
{
path: [
{ TagId: 2, ParentTagId: null, Name: 'women' },
{ TagId: 4, ParentTagId: 2, Name: 'top' },
{ TagId: 8, ParentTagId: 4, Name: 'tshirt' }
]
},
{
path: [
{ TagId: 16, ParentTagId: null, Name: 'men' }
]
}
]
答案 0 :(得分:2)
将输入数据视为树。您想为每个叶生成path
。 leaf是带有TagId
的标记,未被任何其他标记引用为ParentTagId
。
所以最简单的解决方案是:
ParentTagId
值的集合(即具有唯一条目的列表)。对于您的数据,即[2,4,7]
。TagId
不在该集合中的标记来查找您的树叶。对于您的数据,即[5,8,12,16]
。getTagById
以通过其ID检索标记。getPath([], leaf)
的结果推送到数组paths
。之后,paths
包含每个叶子的路径作为标记数组。paths
。第1步的代码:
var parentTagIdSet = [];
for (var i = 0; i < originData.length; ++i) {
var parentTagId = originData[i].ParentTagId;
if (parentTagId != null && parentTagIdSet.indexOf(parentTagId) == -1) {
parentTagIdSet.push(parentTagId);
}
}
第2步的代码:
var leaves = [];
for (var i = 0; i < originData.length; ++i) {
var tag = originData[i];
if (parentTagIdSet.indexOf(tag.TagId) == -1) {
leaves.push(tag);
}
}
第3步的代码:
function getTagById(id) {
for (var i = 0; i < originData.length; ++i) {
var tag = originData[i];
if (tag.TagId == id) {
return tag;
}
}
// If you finish the loop without returning, a ParentTagId is wrong.
return null;
}
第4步的代码:
function getPath(path, currentTag) {
if (currentTag == null) {
// If you end up in here, some ParentTagId was wrong.
path.reverse();
return path;
}
path.push(currentTag);
var parentId = currentTag.ParentTagId;
if (parentId == null) {
path.reverse();
return path;
} else {
return getPath(path, getTagById(parentId));
}
}
第5步的代码:
var paths = [];
for (var i = 0; i < leaves.length; ++i) {
paths.push(getPath([], leaves[i]));
}
答案 1 :(得分:0)
你基本上想要一个具有以下结构的对象......
class Trie implements IteratorAggregate
{
protected $parent;
protected $children = [];
public function insert(Node $node)
{
$node->parent = $this;
$this->children[] = $node;
}
public function findById($id)
{
foreach($this->children as $childNode) {
if ($childNode->TagId === $id) {
return $childNode;
}
if ($childNode->hasChildren()) {
$n = $childNode->findById($id);
if ($n) {
return $n;
}
}
}
}
public function hasChildren()
{
return (bool) count($this->children);
}
public function getIterator()
{
return new ArrayIterator($this->children);
}
}
和节点......
class Node extends Trie
{
public function __construct(stdClass $obj)
{
foreach($obj as $p => $v) {
$this->$p = $v;
}
}
}
您可以遍历对象列表并实例化每个节点,然后将父id为null的对象插入到树的根中,并将具有子节点的节点直接插入其节点。
e.g。
$list = json_decode(<<<'JSON'
[
{ "TagId": 2, "ParentTagId": null, "Name": "women" },
{ "TagId": 5, "ParentTagId": 2, "Name": "bottom" },
{ "TagId": 4, "ParentTagId": 2, "Name": "top" },
{ "TagId": 7, "ParentTagId": 4, "Name": "shirt" },
{ "TagId": 8, "ParentTagId": 4, "Name": "tshirt" },
{ "TagId": 12, "ParentTagId": 7, "Name": "longsleeve" },
{ "TagId": 16, "ParentTagId": null, "Name": "men" }
]
JSON
);
$trie = new Trie;
/* Insert all of the parentless nodes */
foreach($list as $n => $obj) {
if (!$obj->ParentTagId) {
$trie->insert(new Node($obj));
unset($list[$n]);
}
}
/* Insert all of the child nodes */
foreach($list as $n => $obj) {
$p = $trie->findById($obj->ParentTagId);
if ($p) {
$p->insert(new Node($obj));
unset($list[$n]);
}
}
现在,当您在$trie
上进行迭代时,您拥有所有父节点,然后您可以对任何子节点进行迭代,以深入挖掘层次结构。
答案 2 :(得分:0)
效率不高,不是很漂亮,但是JavaScript
var input = [
{ TagId: 2, ParentTagId: null, Name: 'women' },
{ TagId: 5, ParentTagId: 2, Name: 'bottom' },
{ TagId: 4, ParentTagId: 2, Name: 'top' },
{ TagId: 7, ParentTagId: 4, Name: 'shirt' },
{ TagId: 8, ParentTagId: 4, Name: 'tshirt' },
{ TagId: 12, ParentTagId: 7, Name: 'longsleeve' },
{ TagId: 16, ParentTagId: null, Name: 'men' }
]
var output = []
var path = []
function drill(el){
path.push(el)
var val = input.filter(function(e){return e.ParentTagId === el.TagId})
if(val.length > 0)
val.forEach(drill)
else {
var e = path[0]
while(e = findParent(e))
path.unshift(e)
output.push({
path: path
})
path = []
return
}
}
function findParent(el){
return input.filter(function(e){return e.TagId === el.ParentTagId})[0]
}
input.filter(function(e){return e.ParentTagId === null}).forEach(drill)
console.log(output)
&#13;