S
S
Sergey2021-06-16 19:00:31
JavaScript
Sergey, 2021-06-16 19:00:31

How to get the number of occurrences of a key in a deeply nested object (mixed with arrays)?

Need the number of all occurrences of the 'isTaskDone' key in the object.
But an object can be absolutely any nesting and contain arrays, where there can also be objects with the desired key, etc.

For example:

{
    list: [
      {
        isTaskDone:  false,
      },
    ],
    facilities: {
      bigViews: {
        isTaskDone: false,
        views: [
          {
            isTaskDone:  false,: false,
          },
        ],
      },
      facilitiesList: [
        {	
          isTaskDone: false,
        },
        {	
          isTaskDone: false,
        },
        {	
          isTaskDone: false,
          repairList: [
            {
              isTaskDone:  false,
            },
          ],
        },
      ],
    }
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexander, 2021-06-16
@DaveGarrow

You can create a recursive function that "falls" into the depth of the object and checks all the keys Like
this: JSFiddle

the code
const obj = {
  list: [{
    isTaskDone: false,
  }, ],
  facilities: {
    bigViews: {
      isTaskDone: false,
      views: [{
        isTaskDone: false,
        some: false,
      }, ],
    },
    facilitiesList: [{
        isTaskDone: false,
      },
      {
        isTaskDone: false,
      },
      {
        isTaskDone: false,
        repairList: [{
          isTaskDone: false,
        }, ],
      },
    ],
  }
}


const calculeFields = (obj, field = '') => {
  let count = 0;

  const rec = obj => {
  	for( let key in obj ){
    	if( key === field ){
      	count++;
      }
    	if( typeof obj[key] === 'object' ){
      	rec( obj[key] )
      }
    }
  }
  rec( obj );
  return count;
}

console.log( calculeFields( obj, 'isTaskDone' ) );

UPD
I forgot to add that if the object has circular references (some child object refers to its parent), then this code will fall into an infinite loop. All this is solved by the usual marking and checking before recursion.
Like this
const obj = {
  list: [{
    isTaskDone: false,
  }, ],
  facilities: {
    bigViews: {
      isTaskDone: false,
      views: [{
        isTaskDone: false,
        some: false,
      }, ],
    },
    facilitiesList: [{
        isTaskDone: false,
      },
      {
        isTaskDone: false,
      },
      {
        isTaskDone: false,
        repairList: [{
          isTaskDone: false,
        }, ],
      },
    ],
  }
}

obj.clone = obj; // вот эта строчка создаст циркулярную ссылку внутри объекта.


const marks = {
  markKey: 'temp_mark_411212',
  marksArr: []
}

const calculeFields = (obj, field = '') => {
  let count = 0;

  const rec = obj => {
  	if( obj[marks.markKey] ){
  		return;
  	} else {
    	obj[marks.markKey] = true;
      marks.marksArr.push( obj );
    }
  
  	for( let key in obj ){
    	if( key === field ){
      	count++;
      }
    	if( typeof obj[key] === 'object' ){
      	rec( obj[key] )
      }
    }
  }
  rec( obj );
  
  marks.marksArr.forEach( item => delete item[marks.markKey] );
  return count;
}

console.log( calculeFields( obj, 'isTaskDone' ) );

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question