【发布时间】:2018-01-24 21:28:55
【问题描述】:
假设我有这个 ids/categories 树:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
我需要一个函数来根据输入 id 返回所有叶子(端节点)。 但只有来自每个分支中给出的最深 id 的节点。
我不知道怎么解释,这里举几个例子:
f([1]) returns [2,4,5]
f([1,2]) returns [2]
f([1,3]) returns [4]
f([1,2,3]) returns [2,4]
f([3]) returns [4]
f([4]) returns [4]
f[1,6]) returns [2,4,5,8,9]
f[11]) returns [13, 14]
f[10]) returns [13, 14]
我正在使用的树的结构如下:
array(
[category] => Object(Category)
[children] => array(
array(
[category] => Object(Category)
[children] => array(
...
)
[category] => Object(Category)
[children] => array(
...
)
)
如果这样更容易的话,我也有可用的平面数组:
array(
array(id, parent_id),
array(id, parent_id),
etc..
)
经过几个小时或搜索和头发撕裂,我什至不确定这是否有意义。我该怎么做?
更新
根据评论;这里有一些可以复制/粘贴的代码,带有测试用例。
如您所见,它在测试 [4] 和 [10] 中失败。
/*
Test data (tree):
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Test cases:
f([1]) returns [2,4,5]
f([1,2]) returns [2]
f([1,3]) returns [4]
f([1,2,3]) returns [2,4]
f([3]) returns [4]
f([4]) returns [4]
f([1,6]) returns [2,4,5,8,9]
f([11]) returns [13, 14]
f([10]) returns [13, 14]
*/
$test[] = array('in'=>[1], 'out' => [2,4,5]);
$test[] = array('in'=>[1,2], 'out' => [2]);
$test[] = array('in'=>[1,3], 'out' => [4]);
$test[] = array('in'=>[1,2,3], 'out' => [2,4]);
$test[] = array('in'=>[1,2,5], 'out' => [2,5]);
$test[] = array('in'=>[3], 'out' => [4]);
$test[] = array('in'=>[4], 'out' => [4]);
$test[] = array('in'=>[1,6], 'out' => [2,4,5,8,9]);
$test[] = array('in'=>[11], 'out' => [13, 14]);
$test[] = array('in'=>[10], 'out' => [13, 14]);
echo '<pre>';
foreach($test as $t) {
echo 'input: ' . implode(',',$t['in']) .' '.PHP_EOL;
$r = f($t['in']);
echo 'output: ' . implode(',',$r) .' ';
if($r == $t['out']) {
echo '(ok)';
}
else {
echo '(TEST FAIL)'.PHP_EOL;
echo 'got: ' . implode(',',$r) .' '.PHP_EOL;
echo 'expected: ' . implode(',',$t['out']) .' ';
}
echo PHP_EOL.PHP_EOL;
}
function f($ids) {
$nodes = getEndNodes(getTree(), $ids);
return array_map(function($a){return $a['id'];},$nodes);
}
function getEndNodes($tree, $ids, $force=false) {
$end_nodes = array();
foreach($tree as $el) {
if(!empty($el['children'])) {
// if given ids is in some of these children, search only those
$children = array();
foreach($el['children'] as $child) {
if(in_array($child['element']['id'], $ids)) { $children[] = $child; }
}
// if no children in ids, search all (normal search)
if(!empty($children)) {
$end_nodes = array_merge($end_nodes, getEndNodes($children, $ids));
}
// if this element is in the given ids, force search
elseif(in_array($el['element']['id'], $ids)) {
$end_nodes = array_merge($end_nodes, getEndNodes($el['children'], $ids, true));
}
// if this is a force search
elseif($force) {
$end_nodes = array_merge($end_nodes, getEndNodes($el['children'], $ids));
}
else {
// ??
}
}
else {
$end_nodes[] = $el['element'];
}
}
return $end_nodes;
}
function getList() {
$list = array(
array('id'=>1,'parent_id'=>0),
array('id'=>2,'parent_id'=>1),
array('id'=>3,'parent_id'=>1),
array('id'=>4,'parent_id'=>3),
array('id'=>5,'parent_id'=>1),
array('id'=>6,'parent_id'=>0),
array('id'=>7,'parent_id'=>6),
array('id'=>8,'parent_id'=>7),
array('id'=>9,'parent_id'=>7),
array('id'=>10,'parent_id'=>0),
array('id'=>11,'parent_id'=>10),
array('id'=>12,'parent_id'=>11),
array('id'=>13,'parent_id'=>12),
array('id'=>14,'parent_id'=>12),
);
return $list;
}
function getTree() {
$hash = array();
$list = getList();
foreach($list as $el) {
$hash[$el['id']] = array('element' => $el);
}
foreach($hash as $id => &$node) {
if ($parent_id = $node['element']['parent_id']) {
$hash[$parent_id]['children'][] =& $node;
}
else {
$tree[] =& $node;
}
}
unset($node, $hash);
return $tree;
}
输出
input: 1
output: 2,4,5 (ok)
input: 1,2
output: 2 (ok)
input: 1,3
output: 4 (ok)
input: 1,2,3
output: 2,4 (ok)
input: 1,2,5
output: 2,5 (ok)
input: 3
output: 4 (ok)
input: 4
output: (TEST FAIL)
got:
expected: 4
input: 1,6
output: 2,4,5,8,9 (ok)
input: 11
output: 13,14 (ok)
input: 10
output: (TEST FAIL)
got:
expected: 13,14
【问题讨论】:
-
您应该尝试自己编写代码。在doing more research 之后,如果您有问题发布您尝试过的方法,并清楚地解释什么不起作用,并提供a Minimal, Complete, and Verifiable example。阅读How to Ask 一个好问题。请务必take the tour 并阅读this。
-
@JayBlanchard 添加了我的测试代码。