首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >从平面数组数据结构创建嵌套数组

从平面数组数据结构创建嵌套数组
EN

Stack Overflow用户
提问于 2020-06-02 03:20:58
回答 5查看 622关注 0票数 0

我需要创建一个嵌套数组,使用路径作为子对象的引用。例如: 4.1是4的孩子,4.1.1是4.1的孩子,4.2是4的孩子.我有一个平面数组,里面有所有的数据和路径。创建嵌套数组的最佳方法是如何根据其路径将子数组嵌套到其父数组。

输入:

代码语言:javascript
运行
AI代码解释
复制
const list = [
  {
    location: 1,
    path: '4'
  },
  {
    location: 2,
    path: '4.1'
  },  
  {
    location: 3,
    path: '4.1.1'
  },  
  {
    location: 4,
    path: '4.1.2'
  },  
  {
    location: 5,
    path: '4.2'
  },  
  {
    location: 6,
    path: '4.2.1'
  },
  {
    location: 7,
    path: '4.3'
  },
  {
    location: 8,
    path: '4.3.1'
  }
];

输出:

代码语言:javascript
运行
AI代码解释
复制
const  list = [
  {
    location: 1,
    path: '4',
        children: [
            {
            location: 2,
            path: '4.1',
            children: [
                {
                    location: 3,
                    path: '4.1.1'
                },  
                {
                    location: 4,
                    path: '4.1.2'
                },  
            ]
        },  
            {
                location: 5,
                path: '4.2',
                children: [
                    {
                        location: 6,
                        path: '4.2.1'
                    },
                ]
            },  
            {
                location: 7,
                path: '4.3',
                children: [
                    {
                        location: 8,
                        path: '4.3.1'
                    }
                ]
            },
        ]
  },
];

最好的方法是递归。对这个算法有什么建议吗?

EN

回答 5

Stack Overflow用户

发布于 2020-06-02 04:35:29

您可以首先按路径对对象数组进行排序,以便父对象在排序后的数组中始终位于其子对象之前。例如:“4”将在“4.1”之前

现在,您可以创建一个对象,其中的关键字是路径。让我们假设'4‘已经插入到我们的对象中。

代码语言:javascript
运行
AI代码解释
复制
obj = {
  '4': {
    "location": 1,
    "path": "4",    
  }
}

当我们处理'4.1‘时,我们首先检查'4’是否存在于我们的对象中。如果是,我们现在进入它的子对象(如果键‘check’不存在,我们创建一个新的空对象)并检查'4.1‘是否存在。如果不是,我们插入'4.1‘

代码语言:javascript
运行
AI代码解释
复制
obj = {
  '4': {
    "location": 1,
    "path": "4",
    "children": {
      "4.1": {
        "location": 2,
        "path": "4.1"
      }
    }
  }
}

我们对列表中的每个元素重复这个过程。最后,我们只需要将这个对象递归地转换为一个对象数组。

最终代码:

代码语言:javascript
运行
AI代码解释
复制
list.sort(function(a, b) {
  return a.path - b.path;
})

let obj = {}

list.forEach(x => {
  let cur = obj;
  for (let i = 0; i < x.path.length; i += 2) {
    console.log(x.path.substring(0, i + 1))
    if (x.path.substring(0, i + 1) in cur) {
      cur = cur[x.path.substring(0, i + 1)]
      if (!('children' in cur)) {
        cur['children'] = {}
      }
      cur = cur['children']
    } else {
      break;
    }
  }
  cur[x.path] = x;
})

function recurse (obj) {
  let res = [];
  Object.keys(obj).forEach((key) => {
    if (obj[key]['children'] !== null && typeof obj[key]['children'] === 'object') {
      obj[key]['children'] = recurse(obj[key]['children'])
    }
    res.push(obj[key])
  })
  return res;
}

console.log(recurse(obj));
票数 1
EN

Stack Overflow用户

发布于 2020-06-02 13:40:58

要做到这一点,一种方法是使用将路径映射到对象的中间索引,然后通过在索引中查找每个节点及其父节点将列表折叠到一个结构中。如果没有父对象,则将其添加到根对象中。最后,我们返回根对象的子对象。下面是一些代码:

代码语言:javascript
运行
AI代码解释
复制
const restructure = (list) => {
  const index = list .reduce(
    (a, {path, ...rest}) => ({...a, [path]: {path, ...rest}}), 
    {}
  )
  
  return list .reduce((root, {path}) => {
    const node = index [path]
    const parent = index [path .split('.') .slice(0, -1) .join('.')] || root
    parent.children = [...(parent.children || []), node]
    return root
  }, {children: []}) .children
}

const list = [{location: 1, path: '4'}, {location: 2, path: '4.1' }, {location: 3, path: '4.1.1'}, {location: 4, path: '4.1.2'}, {location: 5, path: '4.2'}, {location: 6, path: '4.2.1'}, {location: 7, path: '4.3'}, {location: 8, path: '4.3.1'}]

console.log (restructure (list))
代码语言:javascript
运行
AI代码解释
复制
.as-console-wrapper {min-height: 100% !important; top: 0}

使用索引意味着我们不需要对任何东西进行排序;输入可以是任何顺序。

例如,查找父对象需要用"4.3"替换"4.3.1"并在索引中查找它。当我们尝试"4"时,它会查找空字符串,但找不到它,并使用根节点。

如果您更喜欢正则表达式,您可以使用下面这行稍微短一点的代码:

代码语言:javascript
运行
AI代码解释
复制
    const parent = index [path.replace (/(^|\.)[^.]+$/, '')] || root

但是,对于类似的问题,您可能还想在recent answer中查看一种更优雅的技术。我在这里的答案是,完成了这项工作(有一点丑陋的变化),但这个答案将教你很多关于有效软件开发的知识。

票数 1
EN

Stack Overflow用户

发布于 2020-06-02 16:34:08

我很好奇Scott的链接答案是否能够在不修改的情况下解决这个问题。确实是这样!

代码语言:javascript
运行
AI代码解释
复制
import { tree } from './Tree'
import { bind } from './Func'

const parent = (path = "") =>
  bind
    ( (pos = path.lastIndexOf(".")) =>
        pos === -1
          ? null
          : path.substr(0, pos)
    )

const myTree =
  tree                          // <- make tree
    ( list                      // <- array of nodes
    , node => parent(node.path) // <- foreign key
    , (node, children) =>       // <- node reconstructor
        ({ ...node, children: children(node.path) }) // <- primary key
    )

console.log(JSON.stringify(myTree, null, 2))
代码语言:javascript
运行
AI代码解释
复制
[
  {
    "location": 1,
    "path": "4",
    "children": [
      {
        "location": 2,
        "path": "4.1",
        "children": [
          {
            "location": 3,
            "path": "4.1.1",
            "children": []
          },
          {
            "location": 4,
            "path": "4.1.2",
            "children": []
          }
        ]
      },
      {
        "location": 5,
        "path": "4.2",
        "children": [
          {
            "location": 6,
            "path": "4.2.1",
            "children": []
          }
        ]
      },
      {
        "location": 7,
        "path": "4.3",
        "children": [
          {
            "location": 8,
            "path": "4.3.1",
            "children": []
          }
        ]
      }
    ]
  }
]

Tree模块在this post中共享,下面来看一下提供bindFunc模块-

代码语言:javascript
运行
AI代码解释
复制
// Func.js
const identity = x => x

const bind = (f, ...args) =>
  f(...args)

const raise = (msg = "") => // functional throw
  { throw Error(msg) }

// ...

export { identity, bind, raise, ... }

展开下面的代码片段,在浏览器中验证结果-

代码语言:javascript
运行
AI代码解释
复制
// Func.js
const bind = (f, ...args) =>
  f(...args)
  
// Index.js
const empty = _ =>
  new Map

const update = (r, k, t) =>
  r.set(k, t(r.get(k)))

const append = (r, k, v) =>
  update(r, k, (all = []) => [...all, v])

const index = (all = [], indexer) =>
  all.reduce
      ( (r, v) => append(r, indexer(v), v)
      , empty()
      )
      
// Tree.js
// import { index } from './Index'
function tree (all, indexer, maker, root = null)
{ const cache =
    index(all, indexer)

  const many = (all = []) =>
    all.map(x => one(x))
    
  const one = (single) =>
    maker(single, next => many(cache.get(next)))

  return many(cache.get(root))
}

// Main.js
// import { tree } from './Tree'
// import { bind } from './Func'

const parent = (path = "") =>
  bind
    ( (pos = path.lastIndexOf(".")) =>
        pos === -1
          ? null
          : path.substr(0, pos)
    )

const list =
  [{location:1,path:'4'},{location:2,path:'4.1'},{location:3,path:'4.1.1'},{location:4,path:'4.1.2'},{location:5,path:'4.2'},{location:6,path:'4.2.1'},{location:7,path:'4.3'},{location:8,path:'4.3.1'}]

const myTree =
  tree
    ( list                      // <- array of nodes
    , node => parent(node.path) // <- foreign key
    , (node, children) =>       // <- node reconstructor
        ({ ...node, children: children(node.path) }) // <- primary key
    )

console.log(JSON.stringify(myTree, null, 2))

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62144258

复制
相关文章
小程序中点击子元素事件而不触发父元素的点击事件
在测试小程序的时候,发现了这样的一个bug,点击子元素事件d的时候触发父元素的点击事件,从而执行父级的点击事件,跳转到了父级的点击事件的页面了。
王小婷
2019/02/21
6.1K0
小程序中点击子元素事件而不触发父元素的点击事件
LWN: 在 Linux 上运行 macOS 程序
目前有个名叫Darling的项目活跃度不断提升,这个项目是希望能在Linux上提供一个针对macOS软件的translation layer(翻译层),有点类似Wine这个项目所做的工作。Darling比起Wine来说,成熟度差得尚远,因此开发者们现在仍在尽力能增加更多功能,使得此项目在今后的某一天能够对更多用户提供帮助。
用户6543014
2019/10/25
6.4K0
LWN: 在 Linux 上运行 macOS 程序
MultiButton事件触发型按键驱动模块在高云FPGA上的移植
前两篇文章介绍了letter-shell串口终端和cmd-parse串口命令解析器在高云FPGA GW1NSR-4C SoC上的移植:
单片机点灯小能手
2023/09/23
7152
MultiButton事件触发型按键驱动模块在高云FPGA上的移植
按键事件处理
当按键来临时可能会有三种动作: ACTION_DOWN:按键被按下 ACTION_UP : 按键被释放 ACTION_MULTIPLE : 多次重复的按键事件,可通过getRepeatCount获取次数 按键的动作状态可以通过event.getAction()方法来获取。一般只要down和up两种行为。 按键事件处理 当然按键也有很多标志位,可以通过event.getFlags()方法来获取按键的标志位。 FLAG_SOFT_KEYBOARD:软键盘的按键事件 FLAG_KEEP_TOUCH_MOD
fanfan
2018/01/24
2.5K0
Spark 在Yarn上运行Spark应用程序
在 YARN 中,每个应用程序实例都有一个 ApplicationMaster 进程,该进程是为该应用程序启动的第一个容器。应用程序负责从 ResourceManager 上请求资源。一旦分配了资源,应用程序将指示 NodeManagers 启动容器。ApplicationMasters 消除了对活跃客户端的依赖:启动应用程序的进程可以终止,并且从在集群上由 YARN 管理的进程继续协作运行。
smartsi
2019/08/07
1.9K0
在 WASI 上运行 .NET 7 应用程序
WASI代表 WebAssembly 系统接口,WASI 让沙盒化的 WebAssembly 应用程序通过一系列类似 POSIX 的函数访问底层操作系统,允许独立于浏览器运行 WebAssembly 代码。这是一个高度实验性的项目,但同时也是一个非常有趣的项目,并且有可能为行业的大规模编程范式转变做出贡献,使 WebAssembly 真正无处不在。
张善友
2022/04/28
1.4K0
在 WASI 上运行 .NET 7 应用程序
Docker-compose 运行MySQL 连接不上
千寻简笔记已开源,Gitee与GitHub搜索chihiro-notes,包含笔记源文件.md,以及PDF版本方便阅读,且是用了精美主题,阅读体验更佳,如果文章对你有帮助请帮我点一个Star~
千寻简
2023/11/05
6800
在QEMU上运行OPTEE
TEE越来越成为一种基础的安全技术,optee作为一种优秀的开源TEE OS正吸引了越来越多的厂商,越来越多的学习者,安智客之前也多次介绍过
安智客
2018/07/30
2.6K0
在QEMU上运行OPTEE
win10在html上运行java的applet程序
Applet是采用Java编程语言编写的小应用程序,该程序可以包含在 HTML(标准通用标记语言的一个应用)页中,与在页中包含图像的方式大致相同。
炒香菇的书呆子
2021/05/17
2.4K0
win10在html上运行java的applet程序
【QT】鼠标按键事件 - QMouseEvent & QKeyEvent
事件是应用程序内部或者外部产生的事情或者动作的统称。在 Qt 中使用⼀个对象来表⽰⼀个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本⾝在不同的时刻发出的。当用户按下⿏标、敲下键盘,或者是窗⼝需要重新绘制的时候,都会发出⼀个相应的事件。⼀些事件是在用户操作时发出,如键盘事件、⿏标事件等,另⼀些事件则是由系统本⾝⾃动发出,如定时器事件。常见的 Qt 事件如下:
YoungMLet
2024/07/20
1K0
【QT】鼠标按键事件 - QMouseEvent & QKeyEvent
事件ID20499、事件ID10010、事件ID10016,远程不上
顾名(EVENT_RPCSS_SERVER_START_TIMEOUT)思义(RPCSS服务超时)
Windows技术交流
2021/06/23
3.9K0
排查矩阵按键丢键问题
按键板作为用户交互入口、板载LCD,与主板通过串口通讯。接手别人留下的代码,发现存在按键响应不到的问题。
ManInRoad
2021/02/07
3830
JS常用的按键事件监听
码客说
2023/09/16
6830
在kubernetes上运行WASM负载
WASM一般用在前端业务中,但目前有扩展到后端服务的趋势。本文使用Krustlet 将WASM服务部署到kubernetes。
charlieroro
2021/05/10
1.5K0
在kubernetes上运行WASM负载
在Hadoop上运行Python脚本
之前已经配置好了Hadoop以及Yarn,可那只是第一步。下面还要在上面运行各种程序,这才是最重要的。
py3study
2020/01/06
4.3K0
在OS X上运行Docker
本文介绍了如何在OS X上运行Docker,通过使用boot2docker和VirtualBox,使基于Linux的Docker能在OS X上正常运行。同时,还探讨了如何将现有的基于Linux的Docker容器迁移到基于macOS的Docker。
Techeek
2018/01/04
1.9K0
在OS X上运行Docker
在Android系统上运行frp
一时兴起,想在Android上跑一下frpc,本来以为需要在PC上交叉编译后放到机器上才行,后来发现好像更简单,Android YYDS!
老高的技术博客
2022/12/28
4.3K0
在Android系统上运行frp
div实现绑定按键事件 转
所有的页面都会引用一个公共js代码库base.js,在这个代码库里为document绑定了按键事件,现在需要为某个特殊的custom.html页面定制事件handler。
stys35
2019/04/29
1.2K0
分享QHotKey全局监听按键事件
  QHotKey是一个类,可用于创建热键/全局快捷方式,也就是可在任何地方使用的快捷方式,而与应用程序状态无关。这意味着您的应用程序可以处于活动状态,非活动状态,最小化或根本不可见,并且仍会收到快捷方式。
Qt君
2023/03/17
1.8K0
分享QHotKey全局监听按键事件
小程序可以打破平台限制在硬件设备上运行吗?
在小程序技术日益成熟、生态日益善的前景下,运营者们发现小程序“即用即走、轻量开发”的特点非常契合各种硬件设备的使用场景;开发者们对“一次开发,多端运行”的诉求也变得越来越强烈。
用户10245619
2023/01/11
7660

相似问题

Liquibase错误:找到多个匹配的目录

11

具有多个模式的Liquibase

13

重命名多个目录匹配模式

13

多个目录上的Makefile模式匹配

244

删除与模式匹配的pig目录

10
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文