【问题标题】:restructure json based on parent基于父级重构json
【发布时间】:2020-05-05 18:19:07
【问题描述】:

我正在研究 reduce 在 javascript 中的使用,并且我正在尝试以通用方式重组对象数组 - 需要是动态的。

flowchart - 我完全迷路了

我从这个开始。

每个 ID 都成为一个 Key。 每个 PARENT 都标识它属于哪个 Key。

我有这个:

const in = [
  {
    "id": "Ball",
    "parent": "Futebol"
  },
  {
    "id": "Nike",
    "parent": "Ball"
  },
  {
    "id": "Volley",
    "parent": null
  }
]

我想要这个

out = {
    "Futebol": {
        "Ball": {
            "Nike": {}
        }
    },
    "Volley": {}
}

我试了一下 - 我惨败了。

const tree = require('./mock10.json')

// Every ID becomes a Key.
// Every PARENT identifies which Key it belongs to.
const parsedTree = {}
tree.reduce((acc, item) => {
    if (parsedTree.hasOwnProperty(item.parent)){
        if (parsedTree[`${item.parent}`].length > 0) {
            parsedTree[`${item.parent}`][`${item.id}`] = {}
        } else {
            parsedTree[`${item.parent}`] = { [`${item.id}`]: {} }
        }
    } else {
        // i get lost in logic
    }
}, parsedTree)

console.log(parsedTree)

【问题讨论】:

  • 元素嵌套的数量限制是多少?
  • 我不想考虑限制。为了研究这个,我创建了 3 个模拟:10 个对象中的一个,50 个和 1000 个中的另一个。
  • 如果有无限的关卡,事情就会变得更加复杂......

标签: javascript json data-structures


【解决方案1】:

我尝试了很多方法,但如果我们使用 Array.prototype.reduce 则没有任何效果

由于缺少父母,元素乱序,再加上可以有无限的级别,我真的不相信这个问题可以通过简单的reduce来解决

这段代码在任何情况下都可以工作:
- 如果未声明所有父母
- 如果有无限多个级别
- 如果他们处于混乱状态

const origin = 
      [ { id: 'Ball',    parent: 'Futebol' } 
      , { id: 'Nike',    parent: 'Ball'    } 
      , { id: 'Volley',  parent: null      } 
      , { id: 'lastOne', parent: 'level4'  }  // added
      , { id: 'level4',  parent: 'Nike'    }  // added
      , { id: 'bis',     parent: 'Nike'    }  // added
      ];

const Result  = {}  // guess who ?
  ,   Parents = []  // tempory array to keep parents elements address by key names
  ;
let nbTodo = origin.length // need this one to verify number of elements to track
  ;

// set all the first levels, add a todo flags
origin.forEach(({id,parent},i,ori)=>
  {
  ori[i].todo = true       // adding todo flag
  if (parent===null) 
    {
    Result[id] = {}        // new first level element
    ori[i].todo = false    // one less :)
    nbTodo--
    Parents.push(({ref:id,path:Result[id]}) )             // I know who you are!
    }
  else if (origin.filter(el=>el.id===parent).length===0) // if he has no parent...
    {
    Result[parent] = {}                                 // we create it one
    Parents.push({ref:parent,path:Result[parent]} )
    }
  })

// to put the children back in their parents' arms
while(nbTodo>0) // while there are still some
  {
  origin.forEach(({id,parent,todo},i,ori)=> // little by little we find them all
    {
    if(todo) // got one !
      {
      let pos = Parents.find(p=>p.ref===parent) // have parent already been placed?
      if(pos) 
        {
        ori[i].todo = false          // to be sure not to repeat yourself unnecessarily
        nbTodo--                     // one less :)
        pos.path[id] = {}            // and voila, parentage is done
        Parents.push(({ref:id,path:pos.path[id]}) ) // he can now take on the role of parent
        }
      }
    })
  }
for (let i=origin.length;i--;) { delete origin[i].todo }  // remove todo flags


console.log( JSON.stringify(Result, 0, 2) )
.as-console-wrapper { max-height: 100% !important; top: 0; }

我终于在之前的基础上做了这个,并通过 reduce 完成了第一步......

为了绕过父数组,我创建了一个递归函数,用于通过 parsedTree 结果的级别搜索每个父元素。

代码如下:

const Tree = 
      [ { id: 'Ball',    parent: 'Futebol' } 
      , { id: 'Nike',    parent: 'Ball'    } 
      , { id: 'Volley',  parent: null      } 
      , { id: 'lastOne', parent: 'level4'  }  // added
      , { id: 'level4',  parent: 'Nike'    }  // added
      , { id: 'bis',     parent: 'Nike'    }  // added
      ];


const parsedTree =  Tree.reduce((parTree, {id,parent},i ) => {
  Tree[i].todo = false
  if (parent===null) 
    { parTree[id] = {} }
  else if (Tree.filter(el=>el.id===parent).length===0) // if he has no parent...
    { parTree[parent] = { [id]: {} } }
  else
    { Tree[i].todo = true }
  return parTree
}, {})

function parsedTreeSearch(id, part)  {
  let rep = null
  for(let kId in part) {
    if (kId===id)
      { rep = part[kId] }
    else if (Object.keys(part[kId]).length) 
      { rep = parsedTreeSearch(id, part[kId]) }
    if (rep) break
  }
  return rep
}

while (Boolean(Tree.find(t=>t.todo))) {
  Tree.forEach(({id,parent,todo},i)=>{ // little by little we find them all
    if (todo) {
      let Pelm = parsedTreeSearch(parent, parsedTree)
      if (Boolean(Pelm)) {
        Pelm[id] = {}
        Tree[i].todo = false
} } }) }

for (let i=Tree.length;i--;) { delete Tree[i].todo }  // remove todo flags


console.log( JSON.stringify( parsedTree ,0,2))
.as-console-wrapper { max-height: 100% !important; top: 0; } 

【讨论】:

    【解决方案2】:

    如果reduce解决方案只是一种选择,你可以这样尝试:

    var input = [
      {
        "id": "Ball",
        "parent": "Futebol"
      },
      {
        "id": "Nike",
        "parent": "Ball"
      },
      {
        "id": "Volley",
        "parent": null
      }
    ];
    
    var output = {};
    
    input.forEach(item => {
      var temp = input.find(x => x.id === item.parent);
      if (temp) {
        temp[item.id] = {};
      }
    });
    
    input = input.filter(item => !input.find(x => x.hasOwnProperty(item.id)));
    
    input.forEach(item => {
      if (!item.parent) {
        output[item.id] = {};
      } else {
        for (var [id, value] of Object.entries(item)) {
          if (typeof value === 'object') {
            output[item.parent] = { [item.id]: { id: {} } };
          }
        }
      }
    })
    
    console.log(output);

    【讨论】:

      【解决方案3】:

      您可以为此使用reduce 方法并将每个id 存储在对象的第一级。如果数组中的对象与树结构中的顺序正确,则此解决方案将起作用。

      const data = [{"id":"Futebol","parent":null},{"id":"Ball","parent":"Futebol"},{"id":"Nike","parent":"Ball"},{"id":"Volley","parent":null}]
      
      const result = data.reduce((r, { id, parent }) => {
        if (!parent) {
          r[id] = {}
          r.tree[id] = r[id]
        } else if (r[parent]) {
          r[parent][id] = {}
          r[id] = r[parent][id]
        }
      
        return r
      }, {tree: {}}).tree
      
      console.log(result)

      【讨论】:

      • {"id":"Futebol","parent":null} 在 PO 问题中不存在,但正如您所说:“如果数组中的对象在树结构中的顺序正确,则此解决方案将起作用。”如果只有 最多 3 个级别
      【解决方案4】:

      为你准备了一个工作代码,请随时询问我的实现

      希望对你有帮助:)

      const arrSample = [
        {
          "id": "Ball",
          "parent": "Futebol"
        },
        {
          "id": "Nike",
          "parent": "Ball"
        },
        {
          "id": "Volley",
          "parent": null
        }
      ]
      
      const buildTree = (arr) => {
        return arr.reduce(([tree, treeMap], { id, parent }) => {
          const val = {}
          treeMap.set(id, val)
      
          if (!parent) {
            tree[id] = val
            return [tree, treeMap]
          }
      
          if (!treeMap.has(parent)) {
            const parentVal = { [id]: val }
            treeMap.set(parent, parentVal)
            tree[parent] = parentVal
            return [tree, treeMap]
          }
      
          const newParentValue = treeMap.get(parent)
          newParentValue[id] = val
          treeMap.set(parent, newParentValue)
          return [tree, treeMap]
        }, [{}, new Map()])
      }
      
      const [result] = buildTree(arrSample)
      
      console.log(JSON.stringify(result, 0, 2))

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-31
        • 2021-10-09
        • 1970-01-01
        • 1970-01-01
        • 2016-11-10
        • 1970-01-01
        相关资源
        最近更新 更多