-1

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'
            }]
        }
    }
}

Do anybody know how to implement convertToTree function? We use lodash in my project so that can help with basic operations.

var object = {
    42: "foo", 
    "a.b.c[0].42": "bar",
    "a.b.c[0].43": "zet",
    "a.d.c[0].42": "baz"
};

function convertToTree() {
  // code here
}
        
convertToTree(object) === {
  "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"
        }
      ]
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>

UPD:

I need this transformation for doing such operation in another place of code:

_.result(bar, 'a.b.c[0].42') === 'bar'

You can find _.result function description here.

3 Answers3

2

There's a tiny library that does this: https://github.com/richie5um/flattenjs

console.log(flattened);
// {
//     'a': true,
//     'b.bb[0]': 0,
//     'b.bb[1]': 1,
//     'b.bb[2]': 2,
//     'b.bb[3]': 3,
//     'b.bb[4]': 4
// }

unflattened = FlattenJS.undo(flattened);
console.log(unflattened);
// { a: true, b: { bb: [ 0, 1, 2, 3, 4 ] } }
mik01aj
  • 11,928
  • 15
  • 76
  • 119
1

You need to use a custom function for numerical indices, because lodash treats all numbers and numbers as strings as numbers. It produces sparse elements, which are not wanted here.

function setValue(object, path, value) {
    var last = path.pop();
    path.reduce(function (o, k, i, kk) {
        return o[k] = o[k] || (typeof (i + 1 in kk ? kk[i + 1] : last) === 'number' ? [] : {});
    }, object)[last] = value;
}

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

Object.keys(foo).forEach(function (k) {
    setValue(bar, k.split(/\.|(?=\[)/).map(function (v) { return v.match(/^\[.+\]$/) ? +v.slice(1, -1) : v; }), foo[k]);
});

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

For comparison with lodash

var foo = { 42: 'foo', 'a.b.c[0].42': 'bar', 'a.b.c[0].43': 'zet', 'a.d.c[0].42': 'baz' },
    keys = Object.keys(foo),
    bar = _.zipObjectDeep(keys, keys.map(function (k) { return foo[k]; }));

console.log(bar);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Your first solution is optimal may be, but difficult for support. The problem with sparse elements is not essential for me, I will update my question. The second solution looks good, but unfortunately, lodash#3.10.1 doesn't have _zipObjectDeep_ method. – Dmytro Rudnitskikh Apr 26 '17 at 21:36
  • Well, I would recommend updating your lodash anyway. [lodash-migrate](https://github.com/lodash-archive/lodash-migrate) and [eslint-plugin-lodash](https://github.com/wix/eslint-plugin-lodash) could help you a lot with this process. – mik01aj Apr 27 '17 at 06:06
  • Great utility, thanks! I will discuss with my team today. – Dmytro Rudnitskikh Apr 27 '17 at 08:26
0

My solution which based on @mik01aj answer.

var rawObject = {
    42: "foo", 
    "a.b.c[0].42": "bar",
    "a.b.c[0].43": "zet",
    "a.d.c[0].42": "baz"
};

function convertToTree(rowObjectData) {
  return _.assign(
      {}, 
      rowObjectData, 
      _.reduce(rowObjectData, function (result, value, key) { 
          return _.set(result, key, value); 
      }, {}))
}

var convertedObject = convertToTree(rawObject);
        
console.log(_.result(convertedObject, "a.b.c[0].42") === "bar");
console.log(convertedObject["a.b.c[0].42"] === "bar");
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>