Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES6 - Finding data in nested arrays

In ES6 using find or filter I'm quite comfortable iterating through to find an element in an array using a value.

However, I'm trying to get a value from a parent array based upon a value from a nested array.

For example, in this data structure:

products: [   {     id: 01,     items: [       {         id: 01,         name: 'apple'       },       {         id: 02,         name: 'banana'       },       {         id: 03,         name: 'orange'       }     ]   },   {     id: 02,     items: [       {         id: 01,         name: 'carrot'       },       {         id: 02,         name: 'lettuce'       },       {         id: 03,         name: 'peas'       }     ]   },   {     id: 03,     items: [       {         id: 01,         name: 'eggs'       },       {         id: 02,         name: 'bread'       },       {         id: 03,         name: 'milk'       }     ]   } ] 

If I know the name or id of the object milk, is there a way to find out the id of the element it's nested within?

Currently I have this:

products.find((product) => {   product.find((prod) => {     return prod.name === 'milk';   }); }); 

Which only returns the object containing milk.

like image 449
Toby Avatar asked Oct 13 '16 15:10

Toby


People also ask

How do I access nested arrays?

A nested data structure is an array or object which refers to other arrays or objects, i.e. its values are arrays or objects. Such structures can be accessed by consecutively applying dot or bracket notation.

How do you check if an element is present in an array in JavaScript?

You can use the includes() method in JavaScript to check if an item exists in an array. You can also use it to check if a substring exists within a string. It returns true if the item is found in the array/string and false if the item doesn't exist.

How do you filter nested array of objects in react?

How do I filter nested array in React? You use the . filter method and iterate on items of the array, passing them to a filter function; if the function returns a “truthy” value, you keep the item in the filtered array, if not you don't. So with an array of integers, it could look like this: var myArr = [0, 1, 2];

Which is the best method to find an item in an array of arrays in JavaScript?

JavaScript Demo: Array.find() If you need the index of the found element in the array, use findIndex() . If you need to find the index of a value, use indexOf() . (It's similar to findIndex() , but checks each element for equality with the value instead of using a testing function.)


2 Answers

You have to return something from the callback of the outer find. In fact, for the inner iteration you shouldn't use find but rather some that returns a boolean for whether an element matching the condition exists within the arrray:

products.find((product) => {   return product.items.some((item) => { //^^^^^^     return item.name === 'milk';   }); }); 

or in short:

products.find(product => product.items.some(item => item.name === 'milk')); 

Then check whether find found something (not null!) and get its .id, the result should be 03. Alternatively, you can filter for the products containing milk as an item and then map all the results to their id:

products.filter(product =>   product.items.some(item => item.name === 'milk'); ).map(product =>   product.id ) // [03] 
like image 80
Bergi Avatar answered Sep 24 '22 08:09

Bergi


UPDATE

As Ricardo Marimon commented, reduce does not break so it keeps searching over the array, So with that in mind as I don't like to use for loops imperative way of programming, its possible to break early from a reduce by mutating the used array, but that would also be bad, so instead its possible to make a copy and mutate the copy instead too.

// slice creates a copy of products return products.slice(0).reduce((prev, product, i, arr) => {     console.log(i);     const findItem = prev || product.items.find(item => item.name === 'milk');     if (typeof findItem !== 'undefined') arr.splice(1); // ejects early     return findItem; }, undefined); 

const products = [   {id: 1, items: [     {id: 1, name: 'apple'},     {id: 2, name: 'banana'},     {id: 3, name: 'orange'}   ]},   {id: 2, items: [     {id: 1, name: 'carrot'},     {id: 2, name: 'lettuce'},     {id: 3, name: 'milk'}   ]},   {id: 3, items: [     {id: 1, name: 'eggs'},     {id: 2, name: 'bread'},     {id: 3, name: 'peas'}   ]} ];  const findItem = products.slice(0).reduce((prev, product, i, arr) => {     console.log(i);     const findItem = prev || product.items.find(item => item.name === 'milk');     if (typeof findItem !== 'undefined') arr.splice(1); // ejects early     return findItem; }, undefined);  console.log(findItem);

OLD

The accepted answer didn't do it for me because I wanted the result of the inner find, using both it always gave me the result of the outer filter/find, and I had to use the resulting array to find the value again.

So instead I used reduce with short-circuit to get the inner result.

// undefined as the initial value is necessary, otherwise it gets the first value of the array instead.  return products.reduce((prev, product) => prev || product.items.find(item => item.name === 'milk'), undefined); 

const products = [   {id: 1, items: [     {id: 1, name: 'apple'},     {id: 2, name: 'banana'},     {id: 3, name: 'orange'}   ]},   {id: 2, items: [     {id: 1, name: 'carrot'},     {id: 2, name: 'lettuce'},     {id: 3, name: 'peas'}   ]},   {id: 3, items: [     {id: 1, name: 'eggs'},     {id: 2, name: 'bread'},     {id: 3, name: 'milk'}   ]} ];  console.log(products.reduce((prev, product) => prev || product.items.find(item => item.name === 'milk'), undefined));
like image 21
Gustavo Fenilli Avatar answered Sep 23 '22 08:09

Gustavo Fenilli