如何将树转换为数组?

4

我有一个树形对象,它是一棵不规则的树,每次运行代码时子节点的名称和键值都可能会改变。例如:

{
    addressRouter: 192.168.0.1,   
    addresses: 
        {
            address1: 'A',   

        },
        {
            address2: 'B',   

        },
        {
            ports: [
                {
                    portA: 'C',   
                    portB: null
                },


        }
    route: 'D',

}

因此,名称如'addressRouter'、'addresses'、'address1'等及其键是不可预测的,但我需要将树状对象转换为以下格式的数组:

addressRouter
addresses/address1
addresses/address2
addresses/ports/portA
addresses/ports/portB
route

然后在它们旁边放置它们的键。

我有这个用于构建树的函数,它是正确的:

const iterate = (obj, obj2) => {
  Object.keys(obj).forEach(key => {

    obj2[key] = obj[key];

    if (typeof obj[key] === 'object') {
        iterate(obj[key], obj2)
    }
  })
}

但是在调试后,我意识到它并没有获取到所有的分支。

你能展示一些实际的数组例子吗?你希望最终的JSON表示是什么样子?从你的“格式”描述中我并没有完全理解你想要的输出,是否应该忽略键名并嵌套数组或者还有其他要求? - Jey DWork
@JeyDWork 我想将第一个灰色框中显示的对象转换为第二个灰色框中显示的字符串。我刚意识到我的迭代函数没有覆盖所有分支,所以我认为我需要纠正这个问题。 - Natiya
所以数组应该是 ["addressRouter", "addresses/address1", "addresses/address2", "addresses/ports/portA", "addresses/ports/portB", "route"],完全按照这个格式,忽略原始对象中的值,并使用 / 作为分隔符将键连接在一起? - Jey DWork
@JeyDWork 是的!完全正确! :) - Natiya
@JeyDWork 刚刚找到了一个可能的解决方案,并将其写成了答案。 - Natiya
3个回答

6
我们可以使用递归函数遍历树并以所需格式获取键。
我假设给定树对象中的地址是一个对象数组。
function processTree(obj, rootKey) {
    const arr = [];
    obj && Object.keys(obj).forEach(key => {
        const val = obj[key];  
        if (val && val instanceof Array) {
            val.forEach(item => arr.push(...processTree(item, key)))
        }else if (val && typeof(val) == "object") {
            arr.push(...processTree(val, key));
        }else {
            arr.push(key);
        }
    });
    return rootKey ? arr.map(item => rootKey + "/" + item) : arr;
}

console.log(processTree(tree, null));

结果 : ["addressRouter", "addresses/address1", "addresses/address2", "addresses/ports/portA", "addresses/ports/portB", "route"]


(注:该文本已经是中文)

3
我刚刚写了下面的代码,请看它是否符合您的要求。

const tree = {
  addressRouter: '192.168.0.1',
  addresses: [
    {
      address1: 'A',
    },
    {
      address2: 'B',
    },
    {
      ports: [
        {
          portA: 'C',
          portB: null,
        },
      ],
    },
  ],
  route: 'D',
};
const traverse = (input) => {
  const resultList = [];
  const isEndPoint = (obj) => {
    return typeof obj !== 'object' || obj === null;
  };
  const buildPath = (currentPath, key) =>
    currentPath === '' ? key : `${currentPath}/${key}`;
  const innerTraverse = (tree, currentPath = '') => {
    if (tree !== null && typeof tree === 'object') {
      Object.entries(tree).forEach(([key, value]) => {
        if (isEndPoint(value)) {
          resultList.push(buildPath(currentPath, key));
          return;
        }
        let path = currentPath;
        if (!Array.isArray(tree)) {
          path = buildPath(currentPath, key);
        }
        innerTraverse(value, path);
      });
    }
  };
  innerTraverse(input);
  return resultList;
};

console.log(traverse(tree));
/**
 * [
 * 'addressRouter',
 * 'addresses/address1',
 * 'addresses/address2',
 * 'addresses/ports/portA',
 * 'addresses/ports/portB',
 * 'route'
 * ]
 */


1

我刚刚找到了我需要的循环这里,它的代码如下:

function* traverse(o,path=[]) {

    for (var i of Object.keys(o)) {

        const itemPath = path.concat(i);
        yield [i,o[i],itemPath];

        if (o[i] !== null && typeof(o[i])=="object") {

            //going one step down in the object tree!!

            yield* traverse(o[i],itemPath);
        }
    }
}

那么,如果树形对象(我问题中的第一个灰色框)被命名为“params”,我会这样做:

if (params != null && params != undefined) {
    for(var [key, value, path] of traverse(params)) {
      // do something here with each key and value

        if (typeof value == 'string'){

            var tempName = '';
            for (name in path) {

                //console.log(path[name])

                p= tempName += path[name] + "/" 

            }
        console.log(p, value)

        }
      }
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接