【问题标题】:Javascript - Convert array to recursive object [duplicate]Javascript - 将数组转换为递归对象[重复]
【发布时间】:2021-11-10 09:30:19
【问题描述】:

我有一个递归对象的结构:

const obj = {
  name: 'entity-0',
  children: [{
    name: 'entity-0-0',
    children: []
  }, {
    name: 'entity-0-1',
    children: [{
      name: 'entity-1-0',
      children: []
    }]
  }]
}

我目前正在将其转换为这样的平面数组:

const arr = [];

function convertObjToArr(obj, level, parent) {
  arr.push({ name: obj.name, parent: parent?.name, level });
  obj.children.forEach(v => this.convertObjToArr(v, level + 1, obj));
}

convertObjToArr(obj, 0);

这导致数组看起来像这样:

[
  { name: 'entity-0', level: 0 },
  { name: 'entity-0-0', parent: 'entity-0', level: 1 },
  { name: 'entity-0-1', parent: 'entity-0', level: 1 },
  { name: 'entity-1-0', parent: 'entity-0-1', level:  2}
]

我现在需要做的是扭转这个过程。我将生成的arr 作为输入并得到obj 作为输出。这可能吗?我该怎么做?

据我所知:

function convertArrToObj(iArr) {
  for(let i = 0; i < iArr.length; i++) {
    if(!iArr[i].parent) newObj = { ...iArr[i], children: [] };
    else {
      // this should somehow find iArr[i].parent and insert itself into its children array
    }
  }
}

但是正如你所看到的,它是不完整的,我很确定它不会是递归的,所以如果它的深度超过 1 层,它将无法工作,我不认为。

【问题讨论】:

  • this should somehow find iArr[i].parent 你的意思是像if (newObj[iArr[i].parent])?您只是在问如何根据存储在变量中的键访问对象的子对象吗?
  • 请注意,您的中间格式无法轻易区分一棵树和一棵树的森林,因此这里的答案——以及至少一些来自重复的答案——都包含一个额外的数组包装器。如果你知道你的树是单根树,你可以简单地从结果中取出第一个元素。

标签: javascript arrays object recursion


【解决方案1】:

这可能有效。

如果只有一个根,则取结果数组中的第一个元素。

const arr = [
  { name: 'entity-0', level: 0 },
  { name: 'entity-0-0', parent: 'entity-0', level: 1 },
  { name: 'entity-0-1', parent: 'entity-0', level: 1 },
  { name: 'entity-1-0', parent: 'entity-0-1', level:  2}
];

const convertArrToObj = (arr, parent) => {
    return arr.filter(item => item.parent === parent)
        .reduce((acc, item) => {
            acc.push({name: item.name, children: convertArrToObj(arr, item.name)});
            return acc;
        }, []);
};

const result = convertArrToObj(arr);

console.log(result);

// using map is simpler, advised by Nick Parsons
const convertArrToObj2 = (arr, parent) => {
    return arr.filter(item => item.parent === parent)
        .map(item => ({name: item.name, children: convertArrToObj2(arr, item.name)}));
};

console.log(convertArrToObj2(arr));

【讨论】:

  • 很好,我认为.map() 在这里比.reduce() 更合适。
  • @NickParsons 很好的评论。更好。
  • 请注意,这里的输出看起来像原始数据,除了它被包装在一个额外的数组中。您可以轻松地将其封装在从结果中获取第一个元素的调用中,但这是相当基本的行为,因为中间格式无法轻易区分一棵树和一片树林。
【解决方案2】:

您可以采用一个循环并构建一个新结构。

const
    getTree = (data, root) => {
        const t = {};
        data.forEach(({ name, parent }) => 
            ((t[parent] ??= {}).children ??= []).push(Object.assign(t[name] ??= {}, { name }))
        );
        return t[root].children;
    },
    data = [{ name: "entity-0", parent: undefined, level: 0 }, { name: "entity-0-0", parent: "entity-0", level: 1 }, { name: "entity-0-1", parent: "entity-0", level: 1 }, { name: "entity-1-0", parent: "entity-0-1", level: 2 }],
    tree = getTree(data);

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

【讨论】:

  • 感谢您抽出宝贵时间!那是一些令人生畏的javascript(我喜欢它!)所以我必须做一些单独的阅读来弄清楚它是如何工作的。但似乎它所做的是将我的树结构转换为平面数组,对吗?因为我实际上已经把那部分写下来了(根据我的问题)。我现在需要一种将生成的平面数组转换回树结构的方法。
猜你喜欢
  • 2020-02-06
  • 2018-03-18
  • 2015-04-21
  • 1970-01-01
  • 1970-01-01
  • 2021-04-27
  • 2021-01-04
  • 1970-01-01
  • 2013-05-13
相关资源
最近更新 更多