Home > Software design >  Most efficient way to split string into tree structure
Most efficient way to split string into tree structure

Time:09-12

I have a dynamic array of the string. Each string represents the node of the tree. If any string has "_", I want to split into each node and store it in another array.

For. e.g. '0_2_0_0' needs to split into "0", "0_2", "0_2_0", & "0_2_0_0" then store it in the new array. I've achieved it by using the multiple for loops. I do not think this is the most efficient way of doing it.

let visibleTreeNodes = [];
const treeData = ['0_0', '0_1', '0_2_0_0', '1'];

for (let i = 0; i < treeData.length; i  ) {
    if (treeData[i].includes('_')) {
        const nodesArray = treeData[i].split('_');
        for (let i = 0; i < nodesArray.length; i  ) {
            let node = nodesArray[0];
            for (let j = 0; j <= i; j  ) {
                if (j !== 0) {
                    node = node   '_'   nodesArray[j];
                }
            }
            if (visibleTreeNodes.indexOf(node) === -1) {
                visibleTreeNodes.push(node)
            }
        }

    } else if (visibleTreeNodes.indexOf(treeData[i]) === -1) {
        visibleTreeNodes.push(treeData[i])
    }
}
console.log(treeData);
console.log(visibleTreeNodes);

CodePudding user response:

You could build a tree first and then get the pathes from the keys.

const
    getFlat = object => Object.keys(object).flatMap(k => [
        k,
        ...getFlat(object[k]).map(p => `${k}_${p}`)
    ]),
    data = ['0_0', '0_1', '0_2_0_0', '1'],
    result = getFlat(data.reduce((t, s) => {
        s.split('_').reduce((o, k) => o[k] ??= {}, t);
        return t;
    }, {}));

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

CodePudding user response:

I tried to simplify your equation. I reached this below snippet. It has a forEach and then a while loop inside forEach for every input string.

let visibleTreeNodes = [];
const treeData = ['0_0', '0_1', '0_2_0_0', '1'];

treeData.forEach(x => {
  const arr = x.split("_");
  let i = 0;
  let node = arr[0];

  while (i < arr.length) {
    if (!visibleTreeNodes.includes(node)) {
      visibleTreeNodes.push(node);
    }
    node = [node, arr[i   1]].join("_");
    i  ;
  }
});

console.log(treeData);
console.log(visibleTreeNodes);

You are free to figure out any better solution.

Thanks

CodePudding user response:

A "one-liner":

const treeData = ['0_0', '0_1', '0_2_0_0', '1'];
const visibleTreeNodes = [...new Set(treeData.flatMap(
   s=>s.split('_').reduce((a, si, i)=> [...a, a[i-1] '_' si])
))];// Set used to remove duplicates
console.log(visibleTreeNodes)
though efficiency must be tested - a more concise solution doesn't automatically result in a shorter run time

CodePudding user response:

All that is left for me is to explain (and remember) the part of building the tree by @Nina Scholz. I'll basically rename the variables and use familiar syntax.

// data can be directories lists
const data = ['0_0', '0_1', '0_2_0_0', '1']

// the classic group by using reduce
var result = data.reduce(function(agg, item) {

  // buliding tree path incrementally
  var pointer = agg;
  item.split('_').forEach(function(part) {
    pointer[part] = pointer[part] || {}
    pointer = pointer[part];
  });

  return agg;
}, {});

// result is classic object tree 
console.log(result);

// iterate to print desired output:
function iterate(tree, parent) {
  Object.keys(tree).forEach(function(key) {
    var value = tree[key];
    var full = (parent ? parent   "_"  : '')   key
    console.log(full)
    if (typeof value === 'object') {
      iterate(value, full)
    }
  })
}

iterate(result)
.as-console-wrapper {max-height: 100% !important}

  • Related