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
.
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.
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 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];
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.)
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]
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));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With