当前位置: 首页 > 知识库问答 >
问题:

从平面阵列创建嵌套阵列-数据结构

夏弘义
2023-03-14

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

输入:

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  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'
                    }
                ]
            },
        ]
  },
];

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

共有3个答案

慕河
2023-03-14

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

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))
css prettyprint-override">.as-console-wrapper {min-height: 100% !important; top: 0}
钱跃
2023-03-14

我很好奇斯科特的链接答案是否能够不经修改就解决这个问题。是的!

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))
[
  {
    "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模块在这篇文章中共享,这里有一个关于提供bindFunc模块的窥视-

// Func.js
const identity = x => x

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

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

// ...

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

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

// 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))
黄俊雄
2023-03-14

首先可以按路径对对象数组进行排序,这样父对象在排序后的数组中总是在其子对象之前。例如:“4”将在“4.1”之前

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

obj = {
  '4': {
    "location": 1,
    "path": "4",    
  }
}

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

obj = {
  '4': {
    "location": 1,
    "path": "4",
    "children": {
      "4.1": {
        "location": 2,
        "path": "4.1"
      }
    }
  }
}

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

最终代码:

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));
 类似资料:
  • 我是编程新手,我有一个任务要求从一维数组创建二维数组。我想到了这一点(没有任何外部来源的帮助,因为这会剥夺学习经验)。它适用于我们教授的测试输入,我只是想知道这是一个丑陋/低效的解决方案。 测试输入:twoDArray([1,2,3,4,5],3)输出将是:[[1,2,3],[4,5]]

  • 问题内容: 我想知道从ArrayList转换为Array是否安全/建议?我有一个文本文件,每行一个字符串: 我想将它们读入数组列表,然后将其转换为数组。建议这样做/合法吗? 谢谢 问题答案: 是的,将转换为是安全的。一个好主意取决于您的预期用途。您需要提供的操作吗?如果是这样,请将其保留为。否则转换掉! 输出

  • Array是一个容器,可以容纳固定数量的项目,这些项目应该是相同的类型。 大多数数据结构都使用数组来实现其算法。 以下是理解Array概念的重要术语。 Element - 存储在数组中的每个项称为元素。 Index - 数组中元素的每个位置都有一个数字索引,用于标识元素。 数组表示 可以使用不同语言以各种方式声明数组。 为了说明,我们采取C数组声明。 可以使用不同语言以各种方式声明数组。 为了说明

  • 问题内容: 我正在尝试从JSON创建嵌套的UL。我能够遍历并从对象中获取数据,但是在构建嵌套UL时遇到了麻烦。我认为’.append’方法放置在错误的位置。生成的LI都分组在一起。我如何创建一个循环(或者也可以用另一种方法)来构建带有正确嵌套的子菜单LI的UL?我曾尝试使用其他类似的帖子来解决我的问题,但是我的数据和代码似乎没有任何意义。对此有些不解之举- 我尝试了几种方法来创建此动态列表,但到目

  • 可以通过以下任何数组创建例程或使用低级ndarray构造函数构造新的ndarray对象。 numpy.empty 它创建一个指定形状和dtype的未初始化数组。 它使用以下构造函数 - numpy.empty(shape, dtype = float, order = 'C') 构造函数采用以下参数。 Sr.No. 参数和描述 1 Shape int的int或元组中的空数组的形状 2 Dtype

  • 问题内容: 我正在尝试创建一个矩阵以显示Pandas数据框中的行之间的差异。 我要这样: 要变成这样(差异垂直): 这是可以通过内置函数实现的,还是需要构建一个循环以获得所需的输出?谢谢你的帮助! 问题答案: 这是numpy广播的标准用例: 我们使用values属性访问基础的numpy数组,并引入了一个新轴,因此结果是二维的。 您可以将其与原始系列结合使用: 由于@Divakar,也可以使用以下命