1

Is there a short way to re-assign array that consists of objects into a new one. I want to use Lodash library and can't figure out how to split it inside and concatenate. I need this to build a tree using jstree library

I have something like this:

 [
      {
        'text':'parent 1',
        'children': [
          {
            'text':'children 3'
          }
        ]
      },
      {
        'text':'parent 2',
        'children': []
      },
      {
        'text':'parent 3',
        'children': []
      },
      {
        'text':'parent 1',
        'children': [
          {
            'text':'children 1',
            'children': []
          },
          {
            'text':'children 2',
            'children': []
          }
        ]
      }
    ] 

And I want to have the next after transforming

[
  {
    'text':'parent 2',
    'children': []
  },
  {
    'text':'parent 3',
    'children': []
  },
  {
    'text':'parent 1',
    'children': [
      {
        'text':'children 1',
        'children': []
      },
      {
        'text':'children 2',
        'children': []
      },
      {
        'text':'children 3'
      }
    ]
  }
] 

And I want to combine all objects if 'text' is the same and concatenate their children.

The nested level may be as much as possible, no restriction.

[
  {
    'text':'parent 1',
    'children': [
      {
        'text':'children 2',
        'children': [
          {
            'text':'parent 3',
            'children': [
              {
                'text':'parent 4',
                'children': [
                  ...
                ]
              },
            ]
          },
        ]
      }
    ]
  }
]

Is it possible?

3
  • the best way is to create function to add an element one by one to the tree and return the result tree for each step. But before inserting, you need to check the full tree you have at the current step, (starts empty), compare with all the elements existent in the tree, parents and children.(resistivity maybe?) You can start by the leafs (last children) or the parents, both methods have their own tricks. Commented Oct 18, 2016 at 16:23
  • Could you please post the output you need? Commented Oct 18, 2016 at 17:23
  • @Nidhin Yes, I've added Commented Oct 18, 2016 at 17:37

2 Answers 2

1

If you just want to combine objects with the same 'text' and remove duplicates, one solution using lodash could be:

var d = [{
  'text': 'parent 1',
  'children': []
}, {
  'text': 'parent 2',
  'children': []
}, {
  'text': 'parent 3',
  'children': []
}, {
  'text': 'parent 1',
  'children': [{
    'text': 'children 1',
    'children': []
  }, {
    'text': 'children 2',
    'children': []
  }]
}];

var res = _.reduce(d, (memo, o) => {
  var already = _.find(memo, o1 => o.text === o1.text);
  return already ? (already.children = already.children.concat(o.children), memo) : memo.concat(o);
}, []);
console.log(res);
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>

This solution doesn't cover building a tree of more than two levels though.

UPDATE

Supposing the structure of your array would represent that of a tree: each "level" represents a level of the tree and objects in the same level in the array are in the same level in the array, a possible solution using recursion could be:

var tree = [{
  'text': 'A',
  'children': [{
    'text': 'A.1',
    'children': [{
      'text': 'A.1.1',
      'children': [{
        'text': 'A.1.1.1',
        'children': [{
          'text': 'A.1.1.1.1'
        }]
      }, {
        'text': 'A.1.1.1',
        'children': [{
          'text': 'A.1.1.1.2'
        }]
      }]
    }]
  }, {
    'text': 'A.2',
    'children': [{
      'text': 'A.2.1',
      'children': [{
        'text': 'A.2.1.1',
        'children': []
      }]
    }]
  }]
}, {
  'text': 'B',
  'children': []
}, {
  'text': 'C',
  'children': []
}, {
  'text': 'A',
  'children': [{
    'text': 'A.3',
    'children': []
  }, {
    'text': 'A.4',
    'children': []
  }]
}];

function joinChildren(childrenArray) {
  return _.reduce(childrenArray, function(memo, o) {
    var already = _.find(memo, function(o1) {
      return o.text === o1.text;
    });
    return already ? (already.children = already.children.concat(o.children), memo) : memo.concat(o);
  }, []);
}

function joinChildrenRecursively(rootArray) {
  rootArray = joinChildren(rootArray);
  _.forEach(rootArray, obj => {
    if (_.isArray(obj.children)) {
      obj.children = joinChildrenRecursively(obj.children);
    }
  });
  return rootArray;
}

console.log(joinChildrenRecursively(tree));
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>

Hope it helps.

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

8 Comments

Thank you, it almost does what I want, but children Array consist now of Arrays and not of Objects. Is it possible somehow to change it?
@ConstantineGolub Sure, I've updated the answer with a possible solution. Is the result as expected? thanks!
Thanks, It works now but seems the max nesting level is 2, is it possible to fix it somehow?
@ConstantineGolub You would probably have to use recursion to construct the result. The solution would depend on the data structure that you're working with (how the nodes are within the array). Could you provide a complete example?
I've added the example of nested data to the description of issue
|
1

May be by utilizing the new Object.values() and with pure JS you might do as follows;

var data =  [
      {
        'text':'parent 1',
        'children': [
          {
            'text':'children 3'
          }
        ]
      },
      {
        'text':'parent 2',
        'children': []
      },
      {
        'text':'parent 3',
        'children': []
      },
      {
        'text':'parent 1',
        'children': [
          {
            'text':'children 1',
            'children': []
          },
          {
            'text':'children 2',
            'children': []
          }
        ]
      }
    ],
   nested = Object.values(data.reduce((p,c) => (p[c.text] === undefined ? p[c.text] = {id: c.text, children: c.children}
                                                                        : p[c.text].children.push(...c.children),p), {}));
console.log(nested);

2 Comments

Thanks, right now it has a root for all tree. Is it possible to omit it?
@Constantine Golub You were right i have refactored my code. Check it up :)

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.