Sunny
Sunny

Reputation: 932

Find a nested object inside an arrary of objects based on the string

I've an array of objects in which I need to find the object which has the same value as that of the string. I've tried this and it works.

But, is there a way to optimize it without using map?

Code:

const arr = [{
    label: 'A',
    options: [{
        label: 'abc',
        value: 'abc'
      },
      {
        label: 'bcd',
        value: 'bcd'
      }
    ]
  },
  {
    label: 'B',
    options: [{
        label: 'cde',
        value: 'cde'
      },
      {
        label: 'def',
        value: 'def'
      }
    ]
  },
  {
    label: 'C',
    options: [{
        label: 'efg',
        value: 'efg'
      },
      {
        label: 'fgh',
        value: 'fgh'
      }
    ]
  }
];
const str = 'cde';
const result = arr.map(obj => obj.options.find(item => item.value === str)).find(val => val !== undefined);
console.log('result', result);

Upvotes: 1

Views: 102

Answers (5)

Simeon Ikudabo
Simeon Ikudabo

Reputation: 2190

find in the underscore library will avoid using map in this scenario:

var myObj = _.find(arr, (obj) => {
    return _.find(obj.options, (elt) => elt.value === str);
});

Upvotes: 0

mplungjan
mplungjan

Reputation: 178109

Depending of your needs, you can do this:

const arr = [{ label: 'A', options: [{ label: 'abc', value: 'abc' }, { label: 'bcd', value: 'bcd' }] }, { label: 'B', options: [{ label: 'cde', value: 'cde' }, { label: 'def', value: 'def' } ] }, { label: 'C', options: [{ label: 'efg', value: 'efg' }, { label: 'fgh', value: 'fgh' }] }];

const re1 = /"value":"cde"/
const testStr = JSON.stringify(arr);
console.log(""+testStr)

console.log(re1.test(testStr)) // exists

const re2 = /"label":"(\w)+","value":"cde"/g

console.log(testStr.match(re2)) // label

Upvotes: 0

arizafar
arizafar

Reputation: 3122

you don't need to use find inside the map which is O(nk);

You can fetch all the options then flat the array to find the required object.

const arr = [{
	label: 'A',
	options: [{
			label: 'abc',
			value: 'abc'
		},
		{
			label: 'bcd',
			value: 'bcd'
		}
	]
},
{
	label: 'B',
	options: [{
			label: 'cde',
			value: 'cde'
		},
		{
			label: 'def',
			value: 'def'
		}
	]
},
{
	label: 'C',
	options: [{
			label: 'efg',
			value: 'efg'
		},
		{
			label: 'fgh',
			value: 'fgh'
		}
	]
}
];

const str = 'cde';
const result = arr.map(({options}) => options).flat().find(({value}) => value === str)
console.log('result', result);

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074555

Yes, you don't need or want map followed by find. Just a loop:

let result;
for (const obj of arr) {
    result = obj.options.find(({value}) => value === str);
    if (result) {
        break;
    }
}

Live Example:

const arr = [{
    label: 'A',
    options: [{
        label: 'abc',
        value: 'abc'
      },
      {
        label: 'bcd',
        value: 'bcd'
      }
    ]
  },
  {
    label: 'B',
    options: [{
        label: 'cde',
        value: 'cde'
      },
      {
        label: 'def',
        value: 'def'
      }
    ]
  },
  {
    label: 'C',
    options: [{
        label: 'efg',
        value: 'efg'
      },
      {
        label: 'fgh',
        value: 'fgh'
      }
    ]
  }
];
const str = 'cde';
let result;
for (const obj of arr) {
    result = obj.options.find(({value}) => value === str);
    if (result) {
        break;
    }
}
console.log('result', result);

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386654

You could take Array#flatMap with an empty array as default value.

The result is an array with matching result.

const
    arr = [{ label: 'A', options: [{ label: 'abc', value: 'abc' }, { label: 'bcd', value: 'bcd' }] }, { label: 'B', options: [{ label: 'cde', value: 'cde' }, { label: 'def', value: 'def' } ] }, { label: 'C', options: [{ label: 'efg', value: 'efg' }, { label: 'fgh', value: 'fgh' }] }];
    str = 'cde';
    result = arr.flatMap(obj => obj.options.find(item => item.value === str) || []);

console.log('result', result);

Upvotes: 1

Related Questions