1

How to find an object and parent object in repeatedly nested array of unknown size? Using lodash or native javascript.

Array might be something like this:

var modules = [{
    name: 'Module1',
    submodules: [{
        name: 'Submodule1',
        id: 1,
        submodules: [{
          name: 'Submodule11',
          id: 1,
          submodules: []
        }, {
          name: 'Submodule12',
          id: 2,
          submodules: [{
            name: 'Submodule121',
            id: 1,
            submodules: []
          }, {
            name: 'Submodule122',
            id: 2,
            submodules: []
          }]
        }]
      },
      {
        name: 'Submodule2',
        id: 2,
        submodules: []
      }
    ]
  },
  {
    name: 'Module2',
    submodules: [{
      name: 'Submodule1',
      id: 3,
      submodules: []
    }, {
      name: 'Submodule2',
      id: 4,
      submodules: []
    }]
  }
];

And let's say all the 'name' properties in array are unique.

And I want to find:

name: 'Submodule122'

I was using this function for finding parent object but it works only on first level of array:

_.find(this.modules , function(item) {
            return _.some(item.submodules, { name: 'Submodule122'});

And this to find actual object, but it also works only on first level of array:

_(this.modules)
            .thru(function (coll) {
                return _.union(coll, _.map(coll, 'submodules'));
            })
            .flatten()
            .find({ name: 'Submodule122'})

3 Answers 3

2

You could take an iterative and recursive approach by keeping the actual object as parent.

function find(name, array, parent) {
    var result;
    array.some(object =>
        object.name === name && (result = { object, parent }) || 
        (result = find(name, object.submodules, object))
    );
    return result;
}

var modules = [{ name: 'Module1', submodules: [{ name: 'Submodule1', id: 1, submodules: [{ name: 'Submodule11', id: 1, submodules: [] }, { name: 'Submodule12', id: 2, submodules: [{ name: 'Submodule121', id: 1, submodules: [] }, { name: 'Submodule122', id: 2, submodules: [] }] }, { name: 'Submodule2', id: 2, submodules: [] }] }, { name: 'Module2', submodules: [{ name: 'Submodule1', id: 3, submodules: [] }, { name: 'Submodule2', id: 4, submodules: [] }] }] }];

console.log(find('Submodule122', modules));
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

Comments

0

var modules = [{
    name: 'Module1',
    submodules: [{
        name: 'Submodule1',
        id: 1,
        submodules: [{
          name: 'Submodule11',
          id: 1,
          submodules: []
        }, {
          name: 'Submodule12',
          id: 2,
          submodules: [{
            name: 'Submodule121',
            id: 1,
            submodules: []
          }, {
            name: 'Submodule122',
            id: 2,
            submodules: []
          }]
        }]
      },
      {
        name: 'Submodule2',
        id: 2,
        submodules: []
      }
    ]
  },
  {
    name: 'Module2',
    submodules: [{
      name: 'Submodule1',
      id: 3,
      submodules: []
    }, {
      name: 'Submodule2',
      id: 4,
      submodules: []
    }]
  }
];

var findByName = (name, module, parent, item) => {
  parent.push(...module.filter(x => Array.isArray(x.submodules) && x.submodules.some(y => y.name == name)));
  item.push(...module.filter(y => y.name == name));

  module.forEach(x => {
    if (Array.isArray(x.submodules) && x.submodules.length > 0) {
      findByName(name, x.submodules, parent, item);
    }
  });

}

var parents = [], items = [];
findByName('Submodule12', modules, parents, items);
console.log(parents);
console.log(items);

Comments

0

Not exactly what was asked for, but I thought still worthwhile sharing. We now use object-scan for all our data processing tasks and it's really powerful once you've wrapped your head around it. Here is how you'd answer your questions

Note that this returns all parents, but it's easy enough to pick the ones that you want.

// const objectScan = require('object-scan');

const search = (name, data) => objectScan(['**.name'], {
  rtn: 'parents',
  abort: true,
  filterFn: ({ value }) => value === name
})(data);

const modules = [{ name: 'Module1', submodules: [{ name: 'Submodule1', id: 1, submodules: [{ name: 'Submodule11', id: 1, submodules: [] }, { name: 'Submodule12', id: 2, submodules: [{ name: 'Submodule121', id: 1, submodules: [] }, { name: 'Submodule122', id: 2, submodules: [] }] }] }, { name: 'Submodule2', id: 2, submodules: [] }] }, { name: 'Module2', submodules: [{ name: 'Submodule1', id: 3, submodules: [] }, { name: 'Submodule2', id: 4, submodules: [] }] }];

console.log(search('Submodule122', modules));
/* =>
[ { name: 'Submodule122', id: 2, submodules: [] },
  [ { name: 'Submodule121', id: 1, submodules: [] },
    { name: 'Submodule122', id: 2, submodules: [] } ],
  { name: 'Submodule12',
    id: 2,
    submodules:
     [ { name: 'Submodule121', id: 1, submodules: [] },
       { name: 'Submodule122', id: 2, submodules: [] } ] },
  [ { name: 'Submodule11', id: 1, submodules: [] },
    { name: 'Submodule12',
      id: 2,
      submodules:
       [ { name: 'Submodule121', id: 1, submodules: [] },
         { name: 'Submodule122', id: 2, submodules: [] } ] } ],
  { name: 'Submodule1',
    id: 1,
    submodules:
     [ { name: 'Submodule11', id: 1, submodules: [] },
       { name: 'Submodule12',
         id: 2,
         submodules:
          [ { name: 'Submodule121', id: 1, submodules: [] },
            { name: 'Submodule122', id: 2, submodules: [] } ] } ] },
  [ { name: 'Submodule1',
      id: 1,
      submodules:
       [ { name: 'Submodule11', id: 1, submodules: [] },
         { name: 'Submodule12',
           id: 2,
           submodules:
            [ { name: 'Submodule121', id: 1, submodules: [] },
              { name: 'Submodule122', id: 2, submodules: [] } ] } ] },
    { name: 'Submodule2', id: 2, submodules: [] } ],
  { name: 'Module1',
    submodules:
     [ { name: 'Submodule1',
         id: 1,
         submodules:
          [ { name: 'Submodule11', id: 1, submodules: [] },
            { name: 'Submodule12',
              id: 2,
              submodules:
               [ { name: 'Submodule121', id: 1, submodules: [] },
                 { name: 'Submodule122', id: 2, submodules: [] } ] } ] },
       { name: 'Submodule2', id: 2, submodules: [] } ] },
  [ { name: 'Module1',
      submodules:
       [ { name: 'Submodule1',
           id: 1,
           submodules:
            [ { name: 'Submodule11', id: 1, submodules: [] },
              { name: 'Submodule12',
                id: 2,
                submodules:
                 [ { name: 'Submodule121', id: 1, submodules: [] },
                   { name: 'Submodule122', id: 2, submodules: [] } ] } ] },
         { name: 'Submodule2', id: 2, submodules: [] } ] },
    { name: 'Module2',
      submodules:
       [ { name: 'Submodule1', id: 3, submodules: [] },
         { name: 'Submodule2', id: 4, submodules: [] } ] } ] ]
 */

console.log(search('unknown', modules));
// => undefined
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Comments

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.