使用一次性循环将平面数组转换为树

2023-11-21

SO,

问题

假设我们有具有以下结构的平面数组:

$array = [
  ['level'=>1, 'name' => 'Root #1'],
  ['level'=>1, 'name' => 'Root #2'],
  ['level'=>2, 'name' => 'subroot 2-1'],
  ['level'=>3, 'name' => '__subroot 2-1/1'],
  ['level'=>2, 'name' => 'subroot 2-2'],
  ['level'=>1, 'name' => 'Root #3']
];

问题是 - 转换该数组,使其成为一棵树。从属关系仅由元素顺序和level场地。让我们定义一下children作为存储子节点的维度名称。对于上面的数组,将是:



  array (
    array (
      'level' => 1,
      'name' => 'Root #1',
    ),
    array (
      'level' => 1,
      'name' => 'Root #2',
      'children' => 
      array (
        array (
          'level' => 2,
          'name' => 'subroot 2-1',
          'children' => 
          array (
            array (
              'level' => 3,
              'name' => '__subroot 2-1/1',
            ),
          ),
        ),
        array (
          'level' => 2,
          'name' => 'subroot 2-2',
        ),
      ),
    ),
    array (
      'level' => 1,
      'name' => 'Root #3',
    ),
  )
  

如果不清楚谁是谁的父母,则需要更多说明:以下代码可以轻松可视化想法:

function visualize($array)
{
   foreach($array as $item)
   {
      echo(str_repeat('-', $item['level']).'['.$item['name'].']'.PHP_EOL);
   }
}
visualize($array);

-对于上面的数组来说是:



-[Root #1]
-[Root #2]
--[subroot 2-1]
---[__subroot 2-1/1]
--[subroot 2-2]
-[Root #3]
  

规格

所需的解决方案和输入数组都有一些限制:

  • 输入数组是始终有效:这意味着它的结构总是可以重构为树结构。没有诸如负/非数字级别、没有无效级别结构等奇怪的事情。
  • 输入数组可能很大,目前最大级别不受限制
  • 解决方案must解决问题single循环,所以我们不能将数组分割成块,应用递归或以某种方式在数组中跳转。就简单了foreach(或另一个循环 - 没关系),只有一次,每个元素都应该被逐一处理。

我的方法

目前,我有堆栈的解决方案。我正在处理引用并维护堆栈的当前元素,将在当前步骤中对其进行写入。那是:

function getTree(&$array)
{
   $level = 0;
   $tree  = [];
   $stack = [&$tree];
   foreach($array as $item)
   {
      if($item['level']>$level) //expand stack for new items
      {
         //if there are child elements, add last to stack:
         $top = key($stack);
         if(count($stack[$top]))
         {
            end($stack[$top]);
            $stack[] = &$stack[$top][key($stack[$top])];
         }
         //add ['children'] dim to top stack element
         end($stack);
         $top = key($stack);
         $stack[$top]['children'] = [];
         $stack[] = &$stack[$top]['children'];
      }
      while($item['level']<$level--) //pop till certain level
      {
         //two times: one for last pointer, one for ['children'] dim
         array_pop($stack);
         array_pop($stack);
      }
      //add item to stack top:
      end($stack);
      $stack[key($stack)][] = $item;
      $level = $item['level'];
   }
   return $tree;
}

-因为它足够长,我创建了一个sample使用和输出。

问题

正如您所看到的,我的解决方案很长,它依赖于引用和数组内部指针处理(例如end()), so 问题是:

可能还有其他更短、更清晰的方法来解决这个问题?它看起来像是一些标准问题,但我没有找到任何相应的解决方案(有一个类似的解决方案)question- 但有OP有确切的parent_id服从,而我没有)


关于您的问题的好处是您的输入始终格式正确,因此您的实际问题缩小到为每个节点查找子节点(如果存在)或为每个节点查找父节点(如果有)。后一个在这里更合适,因为我们知道如果该节点的级别大于 1,并且它是初始平面数组中位于该节点之上的最近节点,级别等于当前节点的级别减 1,则该节点有父节点。据此,我们可以只跟踪我们感兴趣的几个节点。更准确地说,每当我们找到具有相同级别的两个节点时,较早找到的节点不能有更多的子节点。

其实现将如下所示:

function buildTree(array &$nodes) {
    $activeNodes = [];

    foreach ($nodes as $index => &$node) {
        //remove if you don't want empty ['children'] dim for nodes without childs
        $node['children'] = [];
        $level = $node['level'];
        $activeNodes[$level] = &$node;

        if ($level > 1) {
            $activeNodes[$level - 1]['children'][] = &$node;
            unset($nodes[$index]);
        }
    }
}

Demo

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用一次性循环将平面数组转换为树 的相关文章

  • 在 CodeIgniter 中将数组与 Calendar 类一起使用

    我正在尝试为我的日历应用程序创建一个相当复杂的数组 它应该包含日期 日期名称 类型 和事件 如果有 我已经创建了这个 dates 22 day gt Friday type gt weekday 23 day gt Saturday typ
  • PHP 中的 Europe/London 和 UTC 有区别吗? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我知道 UTC 和 GMT 实际上是
  • PHP PDO 使用 bindParam 第一个参数(不带冒号)[重复]

    这个问题在这里已经有答案了 请检查这个 user id int GET user id sql DELETE FROM users WHERE user id user id query db gt prepare sql query gt
  • 如何发布数组多维角度js

    我在 angularjs 中有一个数组 示例如下 scope order qty 20 scope order adress Bekasi scope order city Bekasi 这个数组可以用这个代码发布 http method
  • 将变量设置为函数调用以在 PHP 中的 if 语句中使用

    好的 我正在做一些 Wordpress 编辑 并且编写了一个 if 语句 正如您所看到的 这使用函数调用作为变量 这是因为函数调用会调用当前页面的名称 这很好 然而 当我这样做时 它也往往会与页面上的标题相呼应 这是有道理的 我可能正在尝试
  • python - 如何使用for循环重新分配数组中的元素

    我有一个 numpy 浮点数组 我想使用 for 循环重新分配不同的值 但 PyCharm 表示未使用新的变量分配 如果我有 请说 for i in array i i 5 它会说 i 是一个未使用的变量 我究竟做错了什么 您需要为数组元素
  • while 循环中的表并排

    in a while loop its creating a list of heading and image links i want to display it as side by side like in following im
  • 在 woocommerce 管理订单页面中单击自定义按钮运行函数

    基于 在 woocommerce 中的管理订单列表顶部添加一个按钮 https stackoverflow com questions 49437781 add a button on top of admin orders list in
  • 数组与列表的性能

    假设您需要一个需要频繁迭代的整数列表 数组 我的意思是非常频繁 原因可能有所不同 但可以说它位于大容量处理的最内层循环的核心 一般来说 人们会选择使用列表 List 因为它们的大小具有灵活性 最重要的是 msdn 文档声称列表在内部使用数组
  • 如何使用 PHP 从图像文件中读取 Lightroom 关键字?

    我有一个照片社区 www jungledragon com http www jungledragon com 允许用户上传照片 我的平台是 PHP CodeIgniter 作为上传过程的一部分 我已经使用 PHP 读取 EXIF 信息ex
  • 多维数组内的移动

    我有一个用表格显示的数组 如何使用用户输入进行移动 目前 0 被分配给每个数组 但我计划为该数组分配其他值 我的问题是 如何使用用户输入在数组内向上 向下 向右 向左移动和对角移动 Array 0 gt Array 0 gt 0 1 gt
  • Laravel nova diffForHumans 日期时间

    我对用户有字段last active 我想用 diffForHumans 或显示时间time from now来自 Moment js 我怎样才能做到呢 现在我只使用 DateTime make Activiy last active gt
  • 如何使用 jQuery 通过 Ajax 发送复选框数组的值?

    我有一个包含很多表单字段的表单 12 x n 行 每行中的第一个字段 代表产品 是一个类似于以下内容的复选框
  • Paypal IPN 发送“待处理”并以“多币种”为理由?

    我正在使用 Paypal IPN 从我的网站收款 该网站目前仅处于开发阶段 因此我建立了一个沙盒网站进行测试 并且我已经通过在英国注册的测试帐户非常成功地以英镑货币 我的居住国货币 进行付款 但是 我希望该网站能够检测访问者的原籍国并允许他
  • 如何在 JavaScript 中对关联数组进行排序?

    我需要为我的一个项目通过 JS 对关联数组进行排序 我发现这个函数在 Firefox 中运行得很好 但不幸的是它在 IE8 OPERA CHROME 中不起作用 无法找到使其在其他浏览器中运行的方法 或者找到另一个适合该目的的函数 我真的很
  • 如何从 Laravel 中的表中选择所有列名称?

    我试图从表中获取所有列名Teller 功能 public function getTableColumns tables return DB select DB raw SELECT COLUMN NAME DATA TYPE COLUMN
  • Zend Framework 生成唯一的字符串

    我想生成一个唯一的 4 6 个字符长的字母数字字符串 以便与每个记录 用户 一起保存在数据库中 db 字段具有唯一索引 因此尝试保存预先存在的字符串会生成错误 现在我正在生成一个随机字符串并使用 try catch 因此在添加新记录时如果抛
  • PHP 如何判断用户是否按下了 Enter 键或 Submit 按钮?

    我遇到的问题是我在一个表单中有多个提交输入 每个提交输入都有不同的值 我更愿意将它们保留为提交 Whenever the user presses Enter it is as though the topmost submit input
  • gmail 不断阻止 PHPmailer 登录

    我将在接下来的 8 小时内部署一个网站 而 Gmail 刚刚停止接受 PHPmailer 登录我的帐户 起初 它在测试过程中工作了几个小时 然后 它就停止工作了 我已经允许所有允许不太安全的应用程序从 gmail 登录 但它仍然不允许 ph
  • 检查php中位字段是否打开的正确方法是什么

    检查位字段是否打开的正确方法是什么 在 php 中 我想检查来自 db mysql 的位字段是否打开 这是正确的方法吗 if bit 1 还有其他方法吗 我看到有人使用代码ord http jameslow com 2008 08 12 m

随机推荐

  • Doctrine 查询语言获取每组的最大/最新行

    我正在尝试将相对简单的 SQL 语句转换为可在 Doctrine 中运行的语句 但失败了 这是 SQL 语句 它在针对我的数据库运行时按要求工作 SELECT a FROM score a INNER JOIN SELECT name MA
  • 搜索排序矩阵的最有效方法?

    我有一项任务是编写一个算法 不是用任何特定语言 只是伪代码 该算法接收一个矩阵 大小 M x N 该矩阵的排序方式是所有行都已排序 所有列都已排序单独排序 并在该矩阵中找到某个值 我需要编写我能想到的最省时的算法 矩阵看起来像 1 3 5
  • 如何深度克隆iframe?

    有没有办法深度克隆iframe 基本的 jQuery 克隆只是使用相同的 src 创建另一个 iframe 我想要实现的是一种克隆 iframe 的方法 它是准确的当前内容 即任何可能的输入值 通过 javascript 进行的任何 DOM
  • jquery:如何选择没有被 html 标签包围的文本?

    Beer br Vodka br rum br whiskey 如何选择啤酒 还是朗姆酒 在 jquery 中 它们没有被任何 html 标签包围 如果您的意思是要直接选择文本节点 建议不要使用 jQuery 需要澄清的是 获取一组包装的文
  • 我应该将 ASP.NET MVC 控制器操作设为虚拟吗?

    文件 gt ASP NET MVC 项目的新项目 用于生成具有虚拟操作的控制器 我不确定 MVC 2 或 MVC 3 是否会停止这种情况 但这不再是最佳实践吗 T4MVC确实使动作方法变得虚拟 如果您正在使用它 它应该使操作方法变得虚拟 没
  • Python selenium - 修改网页的源代码

    我正在使用 Python selenium 来自动输入我的出勤信息 一切正常 现在我想通过修改源代码来尝试 我看到很少有帖子指出可以使用它进行修改driver execute script 它适用于 JavaScript 但就我而言 我需要
  • 在没有安装 rgdal 的情况下解压并读取 R 中的形状文件

    我想在 R 中解压并读取来自网络的形状文件 而不依赖于 rgdal 我找到了read shp的功能fastshp软件包显然可以在环境中安装 rgdal 的情况下完成此操作 但是 我在实施时遇到了麻烦 我想要一个可以解压缩然后读取形状文件的函
  • 使用 Firebug 检查弹出/下拉菜单样式的技巧是什么?

    有没有办法在使用 Firebug 检查时使弹出菜单 粘住 你可以用 Chrome 来做 但我更喜欢 firebug 当您看不到正在设置样式的元素时 很难设置填充或边距 我做了一些研究但无法弄清楚 有一个内置选项 检查 隐藏 的元素 然后使用
  • 使用构建器模式时“借用的价值不够长”

    我有以下代码 pub struct Canvas lt a gt width isize height isize color Color surface Surface texture Texture renderer a Rendere
  • 更改方法内的引用类型(字符串)

    我将一个字符串变量传递给一个方法 我知道字符串是引用类型 但我在方法内分配的值丢失了 public static void TestMethod string myString myString world static void Main
  • 删除 Swift 3 中的最后一个字符

    我正在创建一个简单的计算器应用程序 目前正在努力在点击按钮时删除最后一个字符 我正在使用dropLast 方法 但我不断收到错误 调用中参数 1 缺少参数 IBAction func onDelPressed button UIButton
  • 正则表达式进入无限循环

    我正在解析以下形式的 物种 名称 Parus Ater H sapiens T rex Tyr rex 通常有两项 二项式 但有时有 3 项或更多项 Troglodytes troglodytes troglodytes E rubecul
  • 来自一系列图像的python 16位灰度视频

    我有一个 uint16 类型的灰度图像数据集 我想将其保存为视频文件 输出应该是 uint16 类型的无损视频文件 我尝试了这个代码 video cv2 VideoWriter file name 0 fps w h isColor Fal
  • “错误时转到 0”和“错误时转到 -1”之间的区别 -- VBA

    谁能找到 VBA 中 On error goto 1 和 on error goto 0 之间的区别吗 我尝试过 google 和 msdn 但没有成功 On Error GoTo 0禁用过程中当前存在的任何错误捕获 On Error Go
  • ASP.NET MVC - Model.OrderBy Date 没有效果

    我在按日期对结果进行排序时遇到一些困难 有什么特别的方法吗 因为我现在正在这样做 var db new DB var articles db Articles var orderedArticles articles OrderBy a g
  • jsp:include 中的 response.sendRedirect() 被忽略?

    我有一个 jsp 文件 其中包含另一个 jsp 文件来检查一些值 例如
  • DataGrid 行的条件文本颜色?

    我有一个绑定到数据库表的数据网格 我需要将行的前景色更改为蓝色 具体取决于其一列中的值 我有办法做到这一点吗 我尝试了 IValueConverter 但我想我一次只能将其用于一个单元格
  • 连接到远程 Spark master - Java / Scala

    我创建了一个 3 节点 1 个主节点 2 个工作节点 Apache SparkAWS 中的集群 我可以从主服务器向集群提交作业 但是我无法让它远程工作 SimpleApp scala import org apache spark Spar
  • 如何在node.js中关闭firebase连接

    下面是我如何使用 firebase 的一个简单示例 let firebase require firebase firebase initializeApp serviceAccount config firebase json datab
  • 使用一次性循环将平面数组转换为树

    SO 问题 假设我们有具有以下结构的平面数组 array level gt 1 name gt Root 1 level gt 1 name gt Root 2 level gt 2 name gt subroot 2 1 level gt