英文:
JSON Tree PHP using a recursive function
问题
问题在于每个子元素都与每个父元素绑定在一起,这就是为什么一切都重复了。
$json = '[
{"id":3633,"name":"Mobile phones and accessories","left":1,"right":18,"level":1,"elements":0},
{"id":3638,"name":"Mobile phones","left":2,"right":3,"level":2,"elements":174},
{"id":21396,"name":"Tablets","left":19,"right":24,"level":1,"elements":0},
{"id":21450,"name":"Some Tablets","left":20,"right":21,"level":2,"elements":8}
]';
$data = json_decode($json, true);
function buildTree($data, $level = 1) {
$tree = array();
foreach ($data as $item) {
if ($item['level'] == $level) {
$node = array(
'item' => $item,
'children' => buildTree($data, $level + 1),
);
$tree[] = $node;
}
}
return $tree;
}
$tree = buildTree($data);
print_r($tree);
原来这是元素的输出。
Array
(
[0] => Array
(
[item] => Array
(
[id] => 3633
[name] => Mobile phones and accessories
[left] => 1
[right] => 18
[level] => 1
[elements] => 0
)
[children] => Array
(
[0] => Array
(
[item] => Array
(
[id] => 3638
[name] => Mobile phones
[left] => 2
[right] => 3
[level] => 2
[elements] => 174
)
[children] => Array
(
)
)
[1] => Array
(
[item] => Array
(
[id] => 21450
[name] => Some Tablets
[left] => 20
[right] => 21
[level] => 2
[elements] => 8
)
[children] => Array
(
)
)
)
)
[1] => Array
(
[item] => Array
(
[id] => 21396
[name] => Tablets
[left] => 19
[right] => 24
[level] => 1
[elements] => 0
)
[children] => Array
(
[0] => Array
(
[item] => Array
(
[id] => 3638
[name] => Mobile phones
[left] => 2
[right] => 3
[level] => 2
[elements] => 174
)
[children] => Array
(
)
)
[1] => Array
(
[item] => Array
(
[id] => 21450
[name] => Some Tablets
[left] => 20
[right] => 21
[level] => 2
[elements] => 8
)
[children] => Array
(
)
)
)
)
)
现在,每个级别为2的元素都与每个级别为1的元素绑定在一起,但不应该有重复。
可以做些什么改变,以使所有元素都是唯一的,并且只属于一个父元素?
英文:
The problem is that each child element is bound to each parent element, which is why everything is duplicated
<?php
$json = '[
{"id":3633,"name":"Mobile phones and accessories","left":1,"right":18,"level":1,"elements":0},
{"id":3638,"name":"Mobile phones","left":2,"right":3,"level":2,"elements":174},
{"id":21396,"name":"Tablets","left":19,"right":24,"level":1,"elements":0},
{"id":21450,"name":"Some Tablets","left":20,"right":21,"level":2,"elements":8}
]';
$data = json_decode($json, true);
function buildTree($data, $level = 1) {
$tree = array();
foreach ($data as $item) {
if ($item['level'] == $level) {
$node = array(
'item' => $item,
'children' => buildTree($data, $level + 1),
);
$tree[] = $node;
}
}
return $tree;
}
$tree = buildTree($data);
print_r($tree);
?>
It turns out that this is the output of the elements
Array
(
[0] => Array
(
[item] => Array
(
[id] => 3633
[name] => Mobile phones and accessories
[left] => 1
[right] => 18
[level] => 1
[elements] => 0
)
[children] => Array
(
[0] => Array
(
[item] => Array
(
[id] => 3638
[name] => Mobile phones
[left] => 2
[right] => 3
[level] => 2
[elements] => 174
)
[children] => Array
(
)
)
[1] => Array
(
[item] => Array
(
[id] => 21450
[name] => Some Tablets
[left] => 20
[right] => 21
[level] => 2
[elements] => 8
)
[children] => Array
(
)
)
)
)
[1] => Array
(
[item] => Array
(
[id] => 21396
[name] => Tablets
[left] => 19
[right] => 24
[level] => 1
[elements] => 0
)
[children] => Array
(
[0] => Array
(
[item] => Array
(
[id] => 3638
[name] => Mobile phones
[left] => 2
[right] => 3
[level] => 2
[elements] => 174
)
[children] => Array
(
)
)
[1] => Array
(
[item] => Array
(
[id] => 21450
[name] => Some Tablets
[left] => 20
[right] => 21
[level] => 2
[elements] => 8
)
[children] => Array
(
)
)
)
)
)
Now I have every element with level = 2 tied to every element with level = 1
But there should be no duplication
What can be changed so that all elements are unique and belong to only one parent
答案1
得分: 1
我看到你的代码中有两个问题:
- 它没有处理当
$level
大于$item['level']
的情况。 - 递归调用使用相同的数组作为第一个参数,但这样做不会保留“指针”位置,并且在每次调用时都会从头开始扫描整个数组。
对于第一个问题,一个简单的if
语句足以解决问题。
对于第二个问题,我建议在不同调用之间使用迭代器来代替数组来保持指针位置。
$data = new ArrayIterator(json_decode($json, true));
function buildTree(iterator $data, int $level = 1): array {
$tree = [];
while ($data->valid()) {
$item = $data->current();
if ($item['level'] < $level)
return $tree;
if ($item['level'] === $level) {
$data->next();
$tree[] = [
'item' => $item,
'children' => buildTree($data, $level + 1)
];
}
}
return $tree;
}
这段代码适用于PHP 8.x,如果需要在旧版本中使用,可以删除函数签名中的类型声明。
英文:
I see two problems in your code:
- it doesn't handle the case when
$level
is greater than$item['level']
- the recursive call uses the same array as first parameter, but doing that doesn't preserve the "pointer" position, and the entire array is scanned at each call from the beginning.
For the first point, a simple if
suffices to solve the problem.
For the second point I suggest to use an iterator in place of an array to keep the pointer positions trough the different calls.
$data = new ArrayIterator(json_decode($json, true));
function buildTree(iterator $data, int $level = 1): array {
$tree = [];
while ($data->valid()) {
$item = $data->current();
if ($item['level'] < $level)
return $tree;
if ($item['level'] === $level) {
$data->next();
$tree[] = [
'item' => $item,
'children' => buildTree($data, $level + 1)
];
}
}
return $tree;
}
This code is written for PHP 8.x, feel free to remove the types in the function signature to make it work with older versions.
答案2
得分: 0
如果您希望按顺序解析它,所有级别1的项目都是兄弟姐妹,否则每个项目都是前一个项目的子项目,那么这里是一个JavaScript伪代码。
var arr = [
{"id":3633,"name":"Mobile phones and accessories","left":1,"right":18,"level":1,"elements":0},
{"id":3638,"name":"Mobile phones","left":2,"right":3,"level":2,"elements":174},
{"id":3639,"name":"Mobile phones 2","left":2,"right":3,"level":3,"elements":174},
{"id":21396,"name":"Tablets","left":19,"right":24,"level":1,"elements":0},
{"id":21450,"name":"Some Tablets","left":20,"right":21,"level":2,"elements":8}
];
var result = [];
var previous = null;
arr.forEach(function(item) {
if (item.level == 1) {
result.push({item})
previous = item;
} else {
previous.children = previous.children || []
previous.children.push({item})
previous = item;
}
})
console.log(result)
请注意,此代码片段是JavaScript的伪代码示例,用于解释结构。
英文:
If you want it by parsed by order, all level 1 are siblings, and otherwise each item is a child of the previous then here's a javascript pseudo-code.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
var arr = [
{"id":3633,"name":"Mobile phones and accessories","left":1,"right":18,"level":1,"elements":0},
{"id":3638,"name":"Mobile phones","left":2,"right":3,"level":2,"elements":174},
{"id":3639,"name":"Mobile phones 2","left":2,"right":3,"level":3,"elements":174},
{"id":21396,"name":"Tablets","left":19,"right":24,"level":1,"elements":0},
{"id":21450,"name":"Some Tablets","left":20,"right":21,"level":2,"elements":8}
];
var result = [];
var previous = null;
arr.forEach(function(item) {
if (item.level == 1) {
result.push({item})
previous = item;
} else {
previous.children = previous.children || []
previous.children.push({item})
previous = item;
}
})
console.log(result)
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论