4

I have a tree object which is an irregular tree which children's names and key values can change everytime I run my code. For example:

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

        },
        {
            address2: 'B',   

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


        }
    route: 'D',

}

so the names: 'addressRouter', 'addresses', 'address1', etc and their keys are unpredictable but I need to convert the tree object in arrays with the following format:

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

and then have their keys next to them.

I have this function to construct the tree, which is correct:

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

    obj2[key] = obj[key];

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

but after debugging, I realized it doesn't get all branches.

Mark
  • 143,421
  • 24
  • 428
  • 436
Natiya
  • 463
  • 2
  • 9
  • 25
  • can you show us actual example arrays how you would them like to be in the end in JSON notation? I don't quite get your desired output from your "format" description, should there be nested arrays ignoring the key names or something else? – Jey DWork Sep 14 '19 at 18:11
  • @JeyDWork I'd like to convert the object shown in the first gray box into the strings shown in the second gray box. I've just realized my iteration function doesn't cover all branches, so I think I need to correct that – Natiya Sep 14 '19 at 21:45
  • So the array should be `["addressRouter", "addresses/address1", "addresses/address2", "addresses/ports/portA", "addresses/ports/portB", "route"]` exactly like that with the values from the original object ignored and the keys joined together with a `/` as delimiter? – Jey DWork Sep 14 '19 at 21:53
  • @JeyDWork yes! exactly! :) – Natiya Sep 15 '19 at 06:16
  • @JeyDWork just find a possible solution and wrote it as an answer – Natiya Sep 15 '19 at 07:54

3 Answers3

6

We can use a recursive function to traverse the tree and get the keys in the required format.

I am assuming addresses in the given tree object is an array of objects

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));

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

Mark
  • 143,421
  • 24
  • 428
  • 436
Abito Prakash
  • 4,368
  • 2
  • 13
  • 26
3

I just write the code below, see if it's what you want.

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'
 * ]
 */
Herb
  • 305
  • 1
  • 7
1

I've just found the loop I needed it here, which is:

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);
        }
    }
}

Then, if the tree object (first gray box in my question) were name, for instance, "params", I would do this:

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)

        }
      }
  }
Natiya
  • 463
  • 2
  • 9
  • 25