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

3

有这个数组:

[
    "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

1
也许可以查看 https://dev59.com/qnM_5IYBdhLWcg3wlEFH 以获取其他选择。 - Nigel Ren
3个回答

1

不必实现递归函数,可以使用内置的array_walk_recursive函数:

$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_recursive 只访问叶子节点,因此除了最内层的 '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);
}

它能够工作……但是它似乎有些不堪重负…… :) - calin24
在哪方面? - lukas.j
不是以负面的方式......乍一看似乎很复杂......但是有意义;-) - calin24
一切都好,我只是好奇! - lukas.j

1

通过遵循您最初的代码,您可以执行以下操作:

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(),只需在根调用时调用一次。


0

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

以下技术将在$structure['all_parents']为真值(非空)时优先考虑递归,并在最深子数组中遇到null all_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',
  ),
)

@calin,你能帮我理解为什么最简洁、最直接的答案,递归和变量更少,却有负面投票吗?如果没有一些逻辑上的原因,我必须假设我的正确/最佳答案只是被人恶意攻击。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接