Javascript: How to filter object in array - javascript

I have an array that is consisted of object which has categoryName(string) field and an array(plants).
I'd like to filter using plant name, what's the best approach?
I tried with but it only returns plants array, ignores categoryName
this.itemList.map(item => item.plants.filter(p=> p.name.toLowerCase().includes(this.searchTerm.toLowerCase())));
Structure
[
[
categoryName: "Heating"
plants: Array(2)
0: {plantId: 35, name: "Alston Oven", description: "Oven", plantCategoryId: 2, whenCreated: "1519357215942", …}
1: {plantId: 19, name: "Gregs Oven", description: null, plantCategoryId: 2, whenCreated: "1516830724579", …}
]
[
categoryName: "Refrigeration"
plants: Array(4)
0: {plantId: 13, name: "Fridge 1 ", description: "Walk in fridge" …}
1: {plantId: 5, name: "Fridge 2 Updated", description: "Description of Fridge 2" …}
2: {plantId: 4, name: "Fridge"....}
]
]

Try:
this.itemList.map(function(a) {
return {
categoryName: a.categoryName,
plants: a.plants.filter(p => p.name.toLowerCase().includes(this.searchTerm.toLowerCase()))
}}).filter(a => a.plants.length > 0)

Use filter() on the outer array and some() on the inner plants array.
This will not filter out the specific plant(s) within the plants array but keep the whole array intact. It is not clear whether you need to filter the sub array or not
const term = this.searchTerm.toLowerCase(),
res = this.itemList.filter(({plants}) => plants.some(({name}) => name.toLowerCase().includes(term)))

Please try this example
const searchTerm = "Alston";
const itemList = [
{
categoryName: "Heating",
plants: [
{
plantId: 35,
name: "Alston Oven",
description: "Oven",
plantCategoryId: 2,
whenCreated: "1519357215942",
},
{
plantId: 19,
name: "Gregs Oven",
description: null,
plantCategoryId: 2,
whenCreated: "1516830724579",
},
],
},
{
categoryName: "Refrigeration",
plants: [
{ plantId: 13, name: "Fridge 1 ", description: "Walk in fridge" },
{
plantId: 5,
name: "Fridge 2 Updated",
description: "Description of Fridge 2",
},
{ plantId: 4, name: "Fridge" },
],
},
];
const output = itemList.filter((item) => {
return item.plants
.map((entry) => entry.name.toLowerCase())
.join()
.includes(searchTerm.toLowerCase());
});
console.dir(output, { depth: null, color: true });
See
Array.prototype.map()
Array.prototype.filter()
Array.prototype.join()

If you just want to filter the plants arrays, you don't need to use map. Use forEach(), and then reassign the plants property with the filtered array there.
this.itemList.forEach(item =>
item.plants = item.plants.filter(p =>
p.name.toLowerCase().includes(this.searchTerm.toLowerCase())));

Related

How to return a new array of objects that contains merged data from source and target?

I want to compare an oldItems array of objects and if id matches the id in my updatedItems array of objects, I want to update the object, copying over the property from oldItems if there is no value in updatedItems for that key or if that property is not defined, and replacing the oldItems object property with the updatedItems object property if there IS a value. I want to store all the changes in a result variable and log result to the console.
The result variable should contain exactly an object with id: 1, the new sandwich name, and the old price, as well as id: 2 with the new price and the new name.
const oldItems = [
{
id: 0,
name: "peanut butter sandwich",
price: 3
},
{
id: 1,
name: "cheese sandwich",
price: 4
},
{
id: 2,
name: "chicken sandwich",
price: 6
}
]
const updatedItems =
[{
id: 1,
name: "grilled cheese sandwich"
}, {
id: 2,
price: 5,
name: "chicken and waffles sandwich"
}]
I tried:
let result = oldItems.map((item, i) => Object.assign({}, item, updatedItems[i]));
console.log(result);
I'm not completely certain of your use-case, but this will produce the result you describe.
oldItems.map(o => {
const update = updatedItems.find(u => u.id === o.id);
if (update) return {
...o,
...update
}
}).filter(x => x)
result :
[
{ id: 1, name: 'grilled cheese sandwich', price: 4 },
{ id: 2, name: 'chicken and waffles sandwich', price: 5 }
]
First, your code maps over the wrong array, you should be mapping updatedItems.
Second, you can't use the same i for both arrays, since the items with the same id are not at the same indexes. Use find() to search the array for the id.
In ES6 you can use ... to merge objects instead of Object.assign().
const oldItems = [{
id: 0,
name: "peanut butter sandwich",
price: 3
},
{
id: 1,
name: "cheese sandwich",
price: 4
},
{
id: 2,
name: "chicken sandwich",
price: 6
}
];
const updatedItems = [{
id: 1,
name: "grilled cheese sandwich"
}, {
id: 2,
price: 5,
name: "chicken and waffles sandwich"
}];
let result = updatedItems.map((item) => ({
...oldItems.find(el => el.id == item.id),
...item
}));
console.log(result);

How to add property value from one array of objects into another (for the matching objects) in JS

I am trying to filter array of objects based on another array of objects and after finding all matching items I want to set property and value from the first array object into corresponding object in the second array:
const searchedProducts = products.filter(product =>
uniqueProducts.some(
uniqueProduct =>
product.productId === uniqueProduct.productId,
),
)
After here I need to set product.productName for each unique product object under productName property.
Ho such a thing can be achieved in a better way?
This is probably most straightforward using reduce() combined with find() to both retrieve and verify that the second array contains each object.
const uniqueProducts = [
{id: 3, from: 'uniqueProducts', name: 'Unique 1'},
{id: 12, from: 'uniqueProducts', name: 'Unique 12'}
];
const products = [
{id: 1, from: 'products', name: 'Product 1'},
{id: 2, from: 'products', name: 'Product 2'},
{id: 9, from: 'products', name: 'Product 9'},
{id: 12, from: 'products', name: 'Product 12'},
];
const output = products.reduce((a, p) => {
const uP = uniqueProducts.find(u => u.id === p.id);
if (uP) a.push({...p, name: uP.name});
return a;
}, []);
console.log(output);
I have inventory where I have to add a price property and take its value from products array so I did this,
inventory = [
{
"productId": 1,
"quantity": 100,
"name": "2 Yolks Noodles",
"image": "twoeggnoodles.jpg",
}
]
Products = [
{
"id": 1,
"quantity": 100,
"name": "2 Yolks Noodles",
"image": "twoeggnoodles.jpg",
"price": 34.95
}
]
let product:any = [];
products.map((prod:any)=>{
const index:any = inventory.find((u:any) => u.productId === prod.id);
// console.log("item", index, '-', prod)
if(index){
product.push({...index, price: prod.price});
}
return prod
})
});

find an object in Array of Array

if i want for an example loop Through this Array to find specific item in Items Array how to approach that? i made this logic but it doesn't work
DATA.map((D)=>{
return D.items.find((item)=>{
return item.name ==='Blue Beanie'
})
})
this is the Array plus how to create new ONE array includes the both of items arrays to be like that: items: [{
id: 1,
name: 'Brown Brim',
price: 25
},
{
id: 2,
name: 'Blue Beanie',
price: 18
},
{
id: 3,
name: 'Adidas NMD',
price: 220
},
{
id: 4,
name: 'Adidas Yeezy',
price: 280
}
]
const DATA= [
{
id: 1,
title: 'Hats',
routeName: 'hats',
items: [
{
id: 1,
name: 'Brown Brim',
price: 25
},
{
id: 2,
name: 'Blue Beanie',
price: 18
}
]
},
{
id: 2,
title: 'Sneakers',
routeName: 'sneakers',
items: [
{
id: 3,
name: 'Adidas NMD',
price: 220
},
{
id: 4,
name: 'Adidas Yeezy',
price: 280
}
]
}
];
Transform DATA into list of items and find from that list your expected item
const res = DATA.flatMap((D) => D.items).find(
(item) => item.name === "Brown Brim"
)
const DATA = [
{
id: 1,
title: "Hats",
routeName: "hats",
items: [
{
id: 1,
name: "Brown Brim",
price: 25,
},
{
id: 2,
name: "Blue Beanie",
price: 18,
},
],
},
{
id: 2,
title: "Sneakers",
routeName: "sneakers",
items: [
{
id: 3,
name: "Adidas NMD",
price: 220,
},
{
id: 4,
name: "Adidas Yeezy",
price: 280,
},
],
},
]
const res = DATA.flatMap((D) => D.items).find(
(item) => item.name === "Brown Brim"
)
console.log(res)
Reference
Array.prototype.flatMap()
Maybe this is helpful?
const DATA= [
{id: 1,title:'Hats',routeName:'hats',
items:[{id: 1,name:"Brown Brim",price:25},
{id: 2,name: 'Blue Beanie',price: 18}]},
{id: 2,title: 'Sneakers',routeName: 'sneakers',
items: [{id: 3,name: 'Adidas NMD',price: 220},
{id: 4,name: 'Adidas Yeezy',price: 280}]}
];
console.log(DATA.map(D=>D.items.find(item=>item.name==='Brown Brim'))
.filter(e=>e))
The .map returns either an element matching your criterion or undefined, The chained .filter then removes all "falsy" elements, i. e. all the undefined ones.
As for the first question "loop Through this Array to find a specific item in Items Array"
given it is not sorted in any way, this can be done by iterating over the DATA array and search inside the items
If want to have access to the item from the outside of the 'forEach' scope you have to declare the variable outside
Regarding the second question, use the reduce function while iterating the array
NOTE: You can obviously combine both tasks as you already iterate through the array, so no need to do it twice. But to avoid confusion, I separated the logic.
Also, if you do choose to combine the tasks, using the reduce is not relevant, but very much like the answer to the first question, you can declare a buffer such as an array, and just copy items to it on the go (I'll leave out questions on performance for that matter)
const DATA = [
{
id: 1, title: 'Hats', routeName: 'hats',
items: [
{id: 1,name: 'Brown Brim',price: 25},
{id: 2,name: 'Blue Beanie',price: 18}
]
},
{
id: 2, title: 'Sneakers', routeName: 'sneakers',
items: [
{id: 3,name: 'Adidas NMD',price: 220},
{id: 4,name: 'Adidas Yeezy',price: 280}
]
}
];
//Question 1
//creating the object that will hold the item
//outside of the 'forEach' scope so we can use it later
let res = {};
const searchRes = DATA.forEach(entry => {
entry.items.forEach(item => {
if (item.name === 'Brown Brim')
//duplicating the item to a variable declared outside of this scope
res = { ...item
};
});
});
console.log(`Q1 - The item we found:`);
console.log(res);
// Question 2
// Merging all object inside the 'items' array using Reduce
const merged = DATA.reduce((acc, curr) =>
acc.concat(curr.items), []);
console.log(`Q2 - The merged array:`);
console.log(merged)

How to groupBy array of objects based on properties in vanilla javascript

How do you groupBy array of objects based on specific properties in vanilla javascript? For example this given:
const products = [
{
category: "Sporting Goods",
price: "$49.99",
stocked: true,
name: "Football"
},
{
category: "Sporting Goods",
price: "$9.99",
stocked: true,
name: "Baseball"
},
{
category: "Sporting Goods",
price: "$29.99",
stocked: false,
name: "Basketball"
},
{
category: "Electronics",
price: "$99.99",
stocked: true,
name: "iPod Touch"
},
{
category: "Electronics",
price: "$399.99",
stocked: false,
name: "iPhone 5"
},
{ category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7" }
];
i want to run a reduce function that would result to a new array of objects like this:
Intended Output:
const categorize = [
{
category:"Sporting Goods",
products: [
{
name:"Football",
price: "$49.99",
stocked: true
},
{
name:"Baseball",
price: "$9.99",
stocked: true
},
{
name:"Basketball",
price: "$29.99",
stocked: true
}
]
},
{
category: "Electronics",
products: [
{
name: "iPod Touch",
price: "$99.99",
stocked: true
},
{
name: "iPhone 5",
price: "$399.99",
stocked: false
},
{
name: "Nexus 7",
price: "$199.99",
stocked: true
}
]
}
]
i based my solution from the tutorial here: https://www.consolelog.io/group-by-in-javascript/ using the reduce function.
Here's my code:
const groupBy = (arr,prop)=>{
return arr.reduce((groups,item)=>{
let val = item[prop];
groups[val] = groups[val]||[];
groups[val].push(item);
return groups
},{});
}
const categorize = groupBy(products,'category');
console.log(categorize);
/* returns an Object like
Object {Sporting Goods: Array[3], Electronics: Array[3]}
however it's not the intended output.
*/
I tried to return Object.values(obj) or Object.entries(obj) inside the groupBy function but it just returns an array of 2 arrays like [Array[3],Array[3]] and if i set the initial value (2nd parameter of reduce) to empty [] instead of {}, the output is just an empty array. Need help, thanks!
Because you want an array containing objects (rather than just an array of plain values), create a { category, products: [] } object if it doesn't exist in the accumulator:
const products=[{category:"Sporting Goods",price:"$49.99",stocked:!0,name:"Football"},{category:"Sporting Goods",price:"$9.99",stocked:!0,name:"Baseball"},{category:"Sporting Goods",price:"$29.99",stocked:!1,name:"Basketball"},{category:"Electronics",price:"$99.99",stocked:!0,name:"iPod Touch"},{category:"Electronics",price:"$399.99",stocked:!1,name:"iPhone 5"},{category:"Electronics",price:"$199.99",stocked:!0,name:"Nexus 7"}];
const output = Object.values(
products.reduce((a, { category, ...item }) => {
if (!a[category]) {
a[category] = { category, products: [] };
}
a[category].products.push(item);
return a;
}, {})
);
console.log(output);
function (){
var map = {};
products.forEach((p) => {
if (map[p.category]) {
var c = p.category;
delete p.category;
map[c].push(p);
} else {
var c = p.category;
delete p.category;
map[c]=[c]
}
});
Object.keys(map).forEach((m) => {
ans.push({category:m, products: map[m]})
})
}
you can collect in one go products and map them.
Then make your resultinng array

Map value of an attribute in one object array to an attribute in another object array Javascript

I have two arrays of objects:
courses = [ { _id: 999, courseCode: "Eng1" },
{ _id: 777, courseCode: "Sci1" },
{ _id: 666, courseCode: "Eng2" },
{ _id: 888, courseCode: "Sci2" } ]
sectionCourses = [ { sectionCode: "1A", courseId: "999" },
{ sectionCode: "1A", courseId: "777" },
{ sectionCode: "2A", courseId: "666" },
{ sectionCode: "2A", courseId: "888" } ]
I want to filter the courses array in such a way that it contains only the courses that are not in a section.
For example if I select section with sectionCode: "2A", the courses array should only contain
courses = [ { _id: 999, courseCode: "Eng1" },
{ _id: 777, courseCode: "Sci1" },
{ _id: 888, courseCode: "Sci2" } ]
I tried to do this way:
courses = courses.filter(c => !(sectionCourses.includes(c._id)))
but I know this is incomplete because I can't figure out how to access courseId in sectionCourses.
Please help.
You can't use .includes() method to find the whole object by its _id, includes compares the whole objects and doesn't search for a specific property.
What you can do here is to get an array of courseIds to be ignored based on the sectionCode you provided, and then filter the courses that their _id doesn't exist in this array of ids:
function getCourses(catCode) {
var coursesIdstoIgnore = sectionCourses.filter(s => s.sectionCode === catCode).map(s => s.courseId);
return courses.filter(c => coursesIdstoIgnore.indexOf(c["_id"].toString()) == -1);
}
Demo:
var courses = [{
_id: 999,
courseCode: "Eng1"
},
{
_id: 777,
courseCode: "Sci1"
},
{
_id: 666,
courseCode: "Eng2"
},
{
_id: 888,
courseCode: "Sci2"
}
];
var sectionCourses = [{
sectionCode: "1A",
courseId: "999"
},
{
sectionCode: "1A",
courseId: "777"
},
{
sectionCode: "2A",
courseId: "666"
},
{
sectionCode: "2A",
courseId: "888"
}
];
function getCourses(catCode) {
var cousesIdstoIgnore = sectionCourses.filter(s => s.sectionCode === catCode).map(s => s.courseId);
console.log(cousesIdstoIgnore);
return courses.filter(c => cousesIdstoIgnore.indexOf(c["_id"].toString()) == -1);
}
var results = getCourses("2A");
console.log(results);
courses.filter(course => sectionCourses.find(section => +section.courseId === +course._id))
Note how i use the +operator before of the courseId and _id properties. this automatically turns a String typed number into a Number.
e.g
+"1" = 1
+1 = 1
This is very useful for slight comparison gotchas when using ===
Note Array.find() doesn't work with IE

Categories

Resources