4
\$\begingroup\$

I want to transform such object from:

foo = {
    42: 'foo', 
    'a.b.c[0].42': 'bar',
    'a.b.c[0].43': 'zet',
    'a.d.c[0].42': 'baz'
}

To:

bar = {
    42: 'foo',
    'a.b.c[0].42': 'bar',
    'a.b.c[0].43': 'zet',
    'a.d.c[0].42': 'baz',
    a: {
        b: {
            c: [{
                42: 'bar', 43: 'zet'
            }]
        },
        d: {
            c: [{
                42: 'baz'
            }]
        }
    }
}

I have written implementation, but it looks ugly. Do anybody know how to improve the function below? We use lodash in my project so that can help with basic operations.

function convertToTree(rowObjectData) {
  function it(object) {
      return _.reduce(object, function (finalObjectData, value, key) {
          var pathParts = key.match(/(.+?)\.(.+)/);

          if (pathParts) {
              delete finalObjectData[key];

              var deepObject = {},
                  containerObject = {},
                  arrayMatch = pathParts[1].match(/(.*)\[(.)]$/);

              deepObject[pathParts[2]] = value;

              if (arrayMatch) {
                  containerObject[arrayMatch[1]] = [];
                  containerObject[arrayMatch[1]][arrayMatch[2]] = it(deepObject);
              } else {
                  containerObject[pathParts[1]] = it(deepObject);
              }

              finalObjectData = _.defaultsDeep(finalObjectData, containerObject);
          }

          return finalObjectData;
      }, object);
  }

  return _.assign(_.cloneDeep(rowObjectData), it(_.cloneDeep(rowObjectData)));
}
        
var object = {
    42: 'foo', 
    'a.b.c[0].42': 'bar',
    'a.b.c[0].43': 'zet',
    'a.d.c[0].42': 'baz'
};
        
console.log(convertToTree(object));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

If I had to take a stab at it I would write something like this:

function convertToTree(rowObjectData) {

  function isArrayKey(key) {
    return _.last(key) == ']';
  }
  
  function setValue(object, value, key) {
    var parts   = key.split(/[.[]/),
        last    = parts.length - 1;

    for (var i=0, current=object; 
         i < parts.length; 
         i++, current = current[k]) {
      var p = parts[i],
          k = isArrayKey(p) ? parseInt(p) : p;
      if (i == last)
        current[k] = value;
      else if (current[k] == undefined)
        current[k] = isArrayKey( parts[i+1] ) ? [] : {}
    } 
    
    return object;
  } 
  
  return _.reduce(rowObjectData, setValue, _.cloneDeep(rowObjectData) );
}
        
var object = {
    42: 'foo', 
    'a.b.c[0].42':    'bar',
    'a.b.c[0].43':    'zet',
    'a.d.c[0].42':    'baz',
    'a.d.c[1]':       'zaphod',
    'a.d.c[2][0].49': 'beeblebrox',
};
        
console.log(convertToTree(object));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>

Which also allows multiple sequential arrays (c[0][1].49 = 'foo' and doesn't require the last key to be an object (c[0] = 'foo')

\$\endgroup\$
1
  • \$\begingroup\$ Thank you, looks good! I found the shorter solution. Please check the same question on stackoverflow. \$\endgroup\$ Commented Apr 26, 2017 at 21:58

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.