根据特定键将对象数组转换为深层嵌套对象

时间:2019-05-06 06:25:27

标签: javascript arrays json recursion javascript-objects

我有一个对象数组。

{
  c1 : ["a1", "c2"],
  c2 : ["b1"],
  c3: ["d1"], 
  b1: ["e"]
  d1: ["k"]
}

我需要按层次结构排列对象。像这样

{ 
   c1: [{a1: null}, {
           c2: [{ 
              b1: "e"
           }]
       }],
   c3: [{ d1: "k" }]
}

请注意,我们可以省略最后一个(最深)键:值对 中的数组。这是我迄今为止尝试过的。

for (v in hash){ 
   hash[v].forEach(function(ar){
    if(hash[ar]){
        if (new_hash[v] == undefined){
            new_hash[v] = []
        }
        new_hash[v].push({[ar] : hash[ar]})
    }
   })
}

我认为这个问题需要动态编程(保存状态的递归),但我这样做不好。请帮忙。

3 个答案:

答案 0 :(得分:2)

您可以获取另一个哈希表并在其中存储所有节点之间的关系,并针对没有父节点的仅结果节点删除该关系。

为了克服没有子节点的问题,我添加了一个空数组,因为原始的所需结构要么具有null要么根本没有子节点(如该节点)

{ b1: "e" }

与空标记一样应为

{ b1: [{ e: null }] }

此解决方案的特征是一个空数组,可以将其替换为任何其他值。

{ b1: [{ e: [] }] }

var hash = { c1: ["a1", "c2"], c2: ["b1"], c3: ["d1"], b1: ["e"], d1: ["k"] },
    keys = Object.keys(hash),
    parents = new Set(keys),
    temp = {},
    tree ;

keys.forEach(k => hash[k].forEach(t => {
    parents.delete(t);
    temp[k] = temp[k] || [];
    temp[t] = temp[t] || [];
    if (!temp[k].some(o => t in o)) temp[k].push({ [t]: temp[t] });
}));

tree = Object.assign({}, ...Array.from(parents, k => ({ [k]: temp[k] })));

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:1)

您可以在没有递归关系的情况下遍历该父母-子女列表。

我省去了将代码实际转换为您描述的格式的代码,因为对我来说这是很早的事情,但是转换应该非常简单。

const data = {
  c1: ["a1", "c2"],
  c2: ["b1"],
  c3: ["d1"],
  b1: ["e"],
  d1: ["k"],
};

// Generate a hash of nodes, mapping them to their children and parents.
const nodes = {};
Object.entries(data).forEach(([parentId, childIds]) => {
  const parent = (nodes[parentId] = nodes[parentId] || {
    id: parentId,
    children: [],
  });
  childIds.forEach(childId => {
    const child = (nodes[childId] = nodes[childId] || {
      id: childId,
      children: [],
    });
    parent.children.push(child);
    child.parent = parent;
  });
});


// Filter in only the nodes with no parents
const rootNodes = {};
Object.values(nodes).forEach(node => {
  // TODO: transform the {id, children, parent} nodes to whichever format you require
  if (!node.parent) rootNodes[node.id] = node;
});

rootNodes看起来像

{
  c1: {
    id: 'c1',
    children: [
      { id: 'a1', children: [], parent: ... },
      {
        id: 'c2',
        children: [
          {
            id: 'b1',
            children: [ { id: 'e', children: [], parent: ... } ],
            parent: ...
          }
        ],
        parent: ...
      }
    ]
  },
  c3: {
    id: 'c3',
    children: [
      {
        id: 'd1',
        children: [ { id: 'k', children: [], parent: ... } ],
        parent: ...
      }
    ]
  }
}

答案 2 :(得分:1)

您可以使用reduce方法创建一个函数来循环Object.keys并构建新的对象结构,还可以使用另一个函数来检查当前键是否已存在于对象中并返回它。

const data = {
  c1: ["a1", "c2"],
  c2: ["b1"],
  c3: ["d1"],
  b1: ["e"],
  d1: ["k"]
}

function find(obj, key) {
  let result = null
  for (let i in obj) {
    if (obj[i] === key || i === key) {
      result = obj
    }

    if (!result && typeof obj[i] == 'object') {
      result = find(obj[i], key)
    }
  }
  return result
}

function nest(data) {
  return Object.keys(data).reduce((r, e) => {
    const match = find(r, e);
    if (match) {
      if (!match[e]) match[e] = []
      match[e].push({
        [data[e]]: null
      })
    } else {
      data[e].forEach(el => {
        if (!r[e]) r[e] = [];
        r[e].push({
          [el]: null
        })
      })
    }
    return r;
  }, {})
}

const result = nest(data);
console.log(result)