let arr = [
{
id:{key:1, name:"apple"},
fruits:[{id:{key:1.1,name:"green apple"}},{id:{key:1.2, name: "red apple"}}]
},
{
id:{key:2, name:"grapes"},
fruits:[{id:{key:2.1,name:"green grapes"}},{id:{key:2.2, name: "black grapes"}}]
},
{
id:{key:3, name:"berries"},
fruits:[{id:{key:3.1,name:"strawberries"}},{id:{key:3.2, name: "blueberries"}}]
},
{
id:{key:4, name:"banana"},
fruits:[{id:{key:4.1,name:"yellow banana"}}]
}
]
const search = "pp"
function filterResult(obj) {
const re = new RegExp(search, "ig")
return re.test(obj.id.name)
}
//this gives result of outer id array only
const searchResult = [
...Object.values(arr).filter((v) => {
let tempArr = [];
if (filterResult(v)) {
tempArr.push(v);
return [...tempArr,...(v.fruits).filter((vv) => {
return filterResult(vv);
})]
}
})
].map((res)=>res.id);
console.log(searchResult);
But now how to search in nested array (fruits) of arr I tried to use flatMap, but I feel i did something wrong.
const searchResult = [
...Object.values(arr).filter((v) => {
let tempArr = [];
if (filterResult(v)) {
tempArr.push(v);
return [...tempArr,...(v.fruits).filter((vv) => {
filterResult(vv);
})]
}
})
]
I want "search Result" result like : because they pp keyword in all ( parent child on same level)
[{id:1, name: "apple"}, {id:1.1,name:"green apple"},{id:1.2, name: "red apple"}]
PS: not allowed to use flatMap
CodePudding user response:
Solution
/**
* Sample data provided.
*/
const arr = [
{
id: { id: 1, name: 'apple' },
fruits: [{ id: 1.1, name: 'green apple' }, { id: 1.2, name: 'red apple' }]
},
{
id: { id: 2, name: 'grapes' },
fruits: [{ id: 2.1, name: 'green grapes' }, { id: 2.2, name: 'black grapes' }]
},
{
id: { id: 3, name: 'berries' },
fruits: [{ id: 3.1, name: 'strawberries' }, { id: 3.2, name: 'blueberries' }]
},
{
id: { id: 4, name: 'banana' },
fruits: [{ id: 4.1, name: 'yellow banana' }]
}
];
/**
* Find all fruits whose name contains the query.
*
* @param {*} array items to iterate through
* @param {*} query search query
* @returns {Array} array of objects whose property name contains the query
*/
const search = (array, query) => {
/**
* MDN documentation on Array.prototype.reduce
* ------------------------------------------------------
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
* ------------------------------------------------------
*/
return array.reduce((acc, item) => {
return [
...acc,
/**
* Add the item to the accumulator if the item name contains the query.
*/
...item.id.name.includes(query) ? [item.id] : [],
/**
* Add all fruits whose name contains the query to the accumulator.
*/
...item.fruits.filter(fruit => fruit.name.includes(query))]
}, []);
};
console.log(search(arr, 'pp'));
Output
[
{ id: 1, name: 'apple' },
{ id: 1.1, name: 'green apple' },
{ id: 1.2, name: 'red apple' }
]
CodePudding user response:
A call of filter
on the input array can only return top level objects, never inner objects. Moreover, it is not necessary to call Object.values
on an array. Just iterate the array.
I would use a recursive generator for this purpose. This way you can have input that is even deeper nested with objects:
function* filterRec(arr, re) {
for (const {fruits, ...obj} of arr) {
if (re.test(obj.name)) yield obj;
if (re.test(obj.id?.name)) yield obj.id;
if (fruits) yield* filterRec(fruits, re);
}
}
const filter = (arr, search) => [...filterRec(arr, RegExp(search, "i"))];
// Demo
const arr = [{id:{id:1, name:"apple"},fruits:[{id:1.1,name:"green apple"},{id:1.2, name: "red apple"}]},{id:{id:2, name:"grapes"},fruits:[{id:2.1,name:"green grapes"},{id:2.2, name: "black grapes"}]},{id:{id:3, name:"berries"},fruits:[{id:3.1,name:"strawberries"},{id:3.2, name: "blueberries"}]},{id:{id:4, name:"banana"},fruits:[{id:4.1,name:"yellow banana"}]}];
const search = "pp"
const searchResult = filter(arr, search);
console.log(searchResult);