使用递归来累积行,而不依赖于类属性变量



拥有此数组:

[
"id" => 5,
"name" => "Item 5",
"all_parents" => [
"id" => 4,
"name" => "Item 4",
"all_parents" => [
"id" => 3,
"name" => "Item 3",
"all_parents" => [
"id" => 2,
"name" => "Item 2",
"all_parents" => [
"id" => 1,
"name" => "Item 1",
"all_parents" => null
]
]
]
]
]

我创建了一个递归php函数,将该数组转换为:

[
["id" => 1, "name" => "Item 1"],
["id" => 2, "name" => "Item 2"],
["id" => 3, "name" => "Item 3"],
["id" => 4, "name" => "Item 4"],
["id" => 5, "name" => "Item 5"],
]

代码是这样的:

private array $breadcrumb = [];
private function generateBreadcrumb($structure) : array
{
if($structure) {
$this->breadcrumb[] = array(
"id" => $structure['id'],
"name" => $structure['name'],
);
$this->generateBreadcrumb($structure['all_parents'] ?? []);
}

return array_reverse($this->breadcrumb);
}

如何在不依赖类属性$breadcrumb的情况下重新设计此方法?

通过遵循初始代码,您可以执行:

function generateBreadcrumb($structure, &$output = []) : array
{
if ($structure) {
$output[] = array(
"id" => $structure['id'],
"name" => $structure['name'],
);
$this->generateBreadcrumb($structure['all_parents'] ?? [], $output);
}
return array_reverse($output);
}

然而,它可以得到改进,至少可以避免每次调用array_reverse(),但仅针对根调用。

与其实现递归函数,不如使用内置的array_walk_recurive函数:

$arr = [
'id'          => 5,
'name'        => 'Item 5',
'all_parents' => [
'id'          => 4,
'name'        => 'Item 4',
'all_parents' => [
'id'          => 3,
'name'        => 'Item 3',
'all_parents' => [
'id'          => 2,
'name'        => 'Item 2',
'all_parents' => [
'id'          => 1,
'name'        => 'Item 1',
'all_parents' => null
]
]
]
]
];
function generateBreadcrumb($structure): array {
$retval = [];
array_walk_recursive($structure, function ($item, $key) use (&$retval) {
if ($key === 'id') {
$retval[] = [$key => $item];
} elseif ($key === 'name') {
$retval[array_key_last($retval)][$key] = $item;
}
});
return array_reverse($retval);
}
$result = generateBreadcrumb($arr);

请注意,array_walk_recurive只访问叶,因此除了最里面的"all_parents"外,其他的都不会访问。

一个非递归版本是这样的:

function generateBreadcrumb(array $arr): array {
$retval = [];
$temp = &$arr;
do {
$retval[] = [ 'id' => $temp['id'], 'name' => $temp['name'] ];
$temp = &$temp['all_parents'];
} while ($temp !== null);
return array_reverse($retval);
}

您可以在递归树时通过合并来累积不确定的深度数据。在递归时,您不需要引入任何新的变量来携带数据,也不需要array_reverse()返回的数据。

以下技术将在$structure['all_parents']为真(非空(时优先考虑递归,并在最深子数组中遇到nullall_parents值时停止递归。从底部开始,idname元素将被访问并合并到行数据的空数组或累积数组中。

代码:(演示(

class Recursing
{
public function generateBreadcrumb(array $structure): array
{
return array_merge(
$structure['all_parents']
? $this->generateBreadcrumb($structure['all_parents'])
: [],
[
['id' => $structure['id'], 'name' => $structure['name']]
]
);
}
}
$test = new Recursing;
var_export($test->generateBreadcrumb($arr));

输出:

array (
0 => 
array (
'id' => 1,
'name' => 'Item 1',
),
1 => 
array (
'id' => 2,
'name' => 'Item 2',
),
2 => 
array (
'id' => 3,
'name' => 'Item 3',
),
3 => 
array (
'id' => 4,
'name' => 'Item 4',
),
4 => 
array (
'id' => 5,
'name' => 'Item 5',
),
)

最新更新