Search code examples
javascriptarraysjstree

Convert 1D array sorted by ASCII order to a nested array in Javascript


Assume this below array of objects that sorted by code property in ascii order:

var codes = [
    { code: '01' },
    { code: '0101' },
    { code: '0102' },
    { code: '010201' },
    { code: '0103' },
    { code: '02' },
    { code: '0201' },
    { code: '0202' },
];

How can I convert this to a nested array like this :

var nestedCodes = [
    {
        code: '01',
        children: [
            { code: '0101' },
            {
                code: '0102',
                children: [
                    { code: '010201' }
                ]
            },
            { code: '0103' }
        ]
    },
    {
        code: '02',
        children: [
            { code: '0201' },
            { code: '0202' }
        ]
    }
];

The structure of codes is like concatenating multiple 0N that N can be a number between 1 and 9. Note that codes come from server and there would be some additional properties beside code like title but it doesn't matter in this problem.

The main idea here is to make an appropriate format for jsTree.


Solution

  • You can do this with a recursive solution. The idea is to maintain the path (obtained as an array via String.prototype.match with a regex) and the parent under which you want to insert the code for each recursive call.

    The parent keeps track of the node you want to pick in the "current" recursive call, and path helps in building the parent as you keep going deeper:

    function insert(d, path, parent, arr) {
      if (path.length === 0) {
        arr.push(Object.assign({}, d));
        return;
      }
      var target = arr.find(e => e.code === parent);
      target.children = target.children || [];
      insert(d, path.slice(1), parent + path[0], target.children);
    }
    
    var codes = [
        { code: '01' },
        { code: '0101' },
        { code: '0102' },
        { code: '010201' },
        { code: '0103' },
        { code: '02' },
        { code: '0201' },
        { code: '0202' },
    ];
    
    var res = codes.reduce((a, c) => {
      var p = c.code.match(/(0[1-9])/g);
      insert(c, p.slice(1), p[0], a);
      return a;
    }, []);
    
    console.log(res);

    The assumption, of course, is that when a code is being inserted, its parent has already been inserted before.