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.

5
  • 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? Commented Sep 14, 2019 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 Commented Sep 14, 2019 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? Commented Sep 14, 2019 at 21:53
  • @JeyDWork yes! exactly! :) Commented Sep 15, 2019 at 6:16
  • @JeyDWork just find a possible solution and wrote it as an answer Commented Sep 15, 2019 at 7:54

3 Answers 3

6
+25

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"]

Sign up to request clarification or add additional context in comments.

Comments

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'
 * ]
 */

Comments

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)

        }
      }
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.