I'm trying to understand the .reduce() function and the best way to go about the following.
I've got the following code:
const products = [
{ name: 'apples', category: 'fruits' },
{ name: 'oranges', category: 'fruits' },
{ name: 'potatoes', category: 'vegetables' }
];
const groupByCategory = products.reduce((group, product) => {
const { category } = product;
group[category] = group[category] ?? [];
group[category].push(product);
return group;
}, {});
I want to add a product with no 'category' property in it, and I want it pushed into a specific key rather than getting grouped in "undefined", so I edited it to:
const products = [
{ name: "apples", category: "fruits" },
{ name: "oranges", category: "fruits" },
{ name: "potatoes", category: "vegetables" },
{ name: "guava"}
];
const groupByCategory = products.reduce((group, product) => {
const { category } = product ;
// check if 'category' exists, if it doesn't store it as an empty array to push to
group[category] = group[category] ?? [];
// if category is undefined, push it into 'nocategory'. Otherwise push into relevant.
if(!category){
group['nocategory'].push(product);
} else {
group[category].push(product);
};
return group;
}, {'nocategory':[]});
console.log(JSON.stringify(groupByCategory, null, 2));
For the most part it works (there's still an 'undefined' group, but at least the object gets pushed into the right group).
I'm sure there's a better solution/proper way to do this. Any pointers would be appreciated.
Instead of a whole new conditional block you could just set a default in the destructuring and then group as usual.
const { category = 'nocategory' } = product;
const products = [
{ name: "apples", category: "fruits" },
{ name: "oranges", category: "fruits" },
{ name: "potatoes", category: "vegetables" },
{ name: "guava"}
];
const groupByCategory = products.reduce((group, product) => {
const { category = 'nocategory' } = product;
group[category] ??= [];
group[category].push(product);
return group;
}, {});
console.log(JSON.stringify(groupByCategory, null, 2));
Note: you can also make use of logical nullish assignment (??=)
You are creating undefined here
group[category] = group[category] ?? []; // category can be undefined
Move creation into if-else statement
const products = [
{ name: "apples", category: "fruits" },
{ name: "oranges", category: "fruits" },
{ name: "potatoes", category: "vegetables" },
{ name: "guava"}
];
const groupByCategory = products.reduce((group, product) => {
const { category } = product ;
// check if 'category' exists, if it doesn't store it as an empty array to push to
// removed
// if category is undefined, push it into 'nocategory'. Otherwise push into relevant.
if(!category){
group['nocategory'].push(product);
} else {
group[category] = group[category] ?? [] // HERE
group[category].push(product);
};
return group;
}, {'nocategory':[]});
console.log(JSON.stringify(groupByCategory, null, 2));
Related
I'm receiving an object like this from the front-end app:
{
name: "Red boys"
category: "Fashion"
subCategory: [
{ name: "sub"},
{ name: "Hub"}
{ name: "Mub"}
// Here it is not static, Here can more or less object in the array
]
}
I have to create a new object from it:
{ category: {name: "Fashion", subCategory: {name: {$in: ["sub", "Hub", "Mub"]}}}}
Here is My Code-
let args = {};
for (let key in filters) {
if (filters[key].length > 0) {
if (key === "category") {
args["category"] = {
name: filters['category'],
// Here I have to check if subCatgory has some value, then create subcategory field
subCategory: {
name: {
$in: [] // Here I can't what I have to wrie
}
}
}
}
}
}
console.log(args);
Pleae help me. I can't understand this functionality. I search but I can get any solutions.
You can destructure the original object, and then restructure the properties from it into a new object. For the sub categories you can map over the array to create an array of objects.
const fe = {
name: 'Red boys',
category: 'Fashion',
subCategory: [
{ name: 'sub' },
{ name: 'Hub' },
{ name: 'Mub' }
]
};
// Get the category and subcategory from the
// object passed from the front-end app
const { category, subCategory } = fe;
// And create a new object
const be = {
category: {
name: 'Fashion',
subCategory: {
name: {
$in: subCategory.map(s => s.name)
}
}
}
};
console.log(be);
Here is the simple solution to the objective:
out.subCategory.name['$in'] = in.subCategory.map( item => item.name );
const inputData = {
name: "Red boys",
category: "Fashion",
subCategory: [
{ name: "sub"},
{ name: "Hub"},
{ name: "Mub"}
]
};
function convertToDesired ( obj ) {
const output = {
category: {
name: obj.category,
subCategory: {
name: {
$in: obj.subCategory.map( item => item.name )
}
}
}
};
return output;
}
console.log(convertToDesired(inputData))
#Suvana
Based on your implementation here is how you can achieve the desired output.
I attached the fiddle code as well.
https://jsfiddle.net/xco7vkn8/1/
for (let key in filters) {
if (filters[key].length > 0) {
if (key === "category") {
args["category"] = {
name: filters['category'],
subcategory:{},
}
}
else if(key ==="subCategory"){
if(filters['subCategory'].length>0){
new_array = [];
filters['subCategory'].forEach(function (item, index) {
new_array.push(item.name);
});
args["category"].subcategory={
name:{
$in:new_array
}
}
}
}
}
}
console.log(args);
I have an array of objects sample for example :
const data = [
{
Name: 'test_1',
Value: '175',
Description: 'desc_1'
},
{
Name: 'test_2',
Value: '175',
Description: 'desc_2'
}
]
And an env file where I mark the data I want :
Name=true
Value=true
Description=false
How do I filter out the data file to only return the values of the keys Name and Value?
Desired output :
[
{
Name: 'test_1',
Value: '175'
},
{
Name: 'test_2',
Value: '175',
}
]
There are different ways in order to achieve the required output, here I'm making use of Array.map and Array.reduce methods.
const data = [{ Name: 'test_1', Value: '175', Description: 'desc_1', }, {Name: 'test_2', Value: '176', Description: 'desc_2', }];
//In order to access from the env file
/*
const fields = {
Name: process.env.Name,
Value: process.env.Value,
Description: process.env.Description
}
*/
//For the snippet purpose i'm using this hardcoded values
const fields = {
Name: true,
Value: true,
Description: false
}
//Convert the object to an array of keys whose values are needed from the original data
const getConfigData = fields => Object.keys(fields).filter(key => fields[key])
let config = getConfigData(fields);
const getSelectedKeyValues = (data, config) => {
return data.map(obj => config.reduce((acc, c) => (acc[c] = obj[c], acc), {}));
}
console.log("Name & Value:", getSelectedKeyValues(data, config));
.as-console-wrapper {
max-height: 100% !important;
}
You can do it like this:
const data = [
{ Name: 'test_1', Value: '175', Description: 'desc_1' },
{ Name: 'test_2', Value: '175', Description: 'desc_2' }
]
let results = data.map((item) => {
new_item = {};
if (process.env.Name) new_item.Name = item.Name;
if (process.env.Value) new_item.Value= item.Value;
if (process.env.Description) new_item.Description= item.Description;
return new_item;
})
Since your example is a JS array and no JSON string, you can use map:
const result = data.map(d => { return {Name: d.name, Value: d.Value }});
Another solution would be filtering the objects entries when mapping and creating a new object from those entries.
const data = [{
Name: 'test_1',
Value: '175',
Description: 'desc_1'
},
{
Name: 'test_2',
Value: '175',
Description: 'desc_2'
}
]
const status = {
Name: true,
Value: true,
Description: false
}
// props you want to keep
const keep = Object.keys(status).filter((k) => status[k]);
const result = data.map((d) => {
// create object from entries based on what you want to keep
return Object.fromEntries(Object.entries(d).filter(([k]) => {
return keep.includes(k)
}));
})
console.log(result);
i have a javascript array who look like this
[
{ quantity: 1, name: 'Menu sandwichs' },
{ quantity: 1, name: 'Menu sandwichs' },
{ quantity: 1, name: 'Menu sandwichs' },
{ quantity: 1, name: 'Pizza' },
{ quantity: 1, name: 'Piza' }
]
and i want to get this array
[
{ quantity:3, name:'Menu Sandwich' },
{ quantity:2, name:'Pizza' }
]
Could you hel me please ?
Assuming the quantities in the original array may sometimes be something other than 1:
const mergeQuantities = (values) => {
const result = {}
values.forEach(({ quantity, name }) => {
result[name] = result[name] || { name, quantity: 0 }
result[name].quantity += quantity
})
return Object.values(result)
}
This creates a new object where the attribute names are the name from each thing in the array. Then iterates over the list, adding each quantity to the result. Finally, it discards the keys, leaving just the array in the form you want.
I have these two arrays, I want to check if the titles and keys match and then push the count from typesCount into types.
I have tried to do a map within a map to check the values against each other and produce a new array but it has not worked.
const types = [
{
title: 'House',
slug: 'house',
count: 0,
},
{
title: 'Car',
slug: 'car',
count: 0,
},
{
title: 'Bike',
slug 'bike',
count: 0,
},
];
const typesCount = [
{
key: 'House',
count: '11',
},
{
key: 'Bike',
count: '22',
},
];
What I've tried so far
const checkForCount = typesCount.map( x => ({
types.map( y => ({
title: y.title,
slug: y.slug,
count: y.title === x.key : x.count ? y.count,
}));
}));
This can be done by using map and find like below
const types = [{title:'House',slug:'house',count:0,},{title:'Car',slug:'car',count:0,},{title:'Bike',slug:'bike',count:0,},];
const typesCount = [{key:'House',count:'11',},{key:'Bike',count:'22',},];
//Loop through the actual array
const res = types.map(type => ({
...type,
//find if the object is present in counts array else use `{}`
count:(typesCount.find(tCount => tCount.key === type.title) || {}).count || type.count
}))
console.log(res)
This can also be done in another way by using reduce and map like below
const types = [{title:'House',slug:'house',count:0,},{title:'Car',slug:'car',count:0,},{title:'Bike',slug:'bike',count:0,},];
const typesCount = [{key:'House',count:'11',},{key:'Bike',count:'22',},];
//use reduce to format the counts like {House:"11",Bike:"22"}. This will be used while updateing the counts in the actual data
const formattedCounts = typesCount.reduce((res, obj) => {
res[obj.key] = obj.count;
return res
}, {})
const result = types.map(type => ({
...type,
//getting the count from formattedCounts object
count: formattedCounts[type.title] || type.count
}))
console.log(result)
Hope this helps.
Please try the following solution
const types = [
{
title: "House",
slug: "house",
count: 0,
},
{
title: "Car",
slug: "car",
count: 0,
},
{
title: "Bike",
slug: "bike",
count: 0,
},
];
const typesCount = [
{
key: "House",
count: "11",
},
{
key: "Bike",
count: "22",
},
];
const output = types.reduce((previousValue, currentValue) => {
const entry = typesCount.find(({ key }) => key === currentValue.title);
if (entry) {
currentValue = { ...currentValue, count: entry.count };
}
previousValue = [...previousValue, currentValue];
return previousValue;
}, []);
console.log(output);
See
Array.prototype.reduce()
You can make a Map of keys and counts from your typesCount, which looks something like so:
{
House => 11,
Bike => 22
}
You can then use .map() on your types array, where, for each object, you use the spread syntax to spread the object properties into a new object literal. You can then update the count property to be one from the map you made if it exists, if it doesn't you can default the value to the current count value of the current object.
See example below:
const types = [ { title: 'House', slug: 'house', count: 0, }, { title: 'Car', slug: 'car', count: 0, }, { title: 'Bike', slug: 'bike', count: 0, }, ];
const typesCount = [ { key: 'House', count: '11', }, { key: 'Bike', count: '22', }, ];
const counts = new Map(typesCount.map(({key, count}) => [key, count]));
const res = types.map(o => ({...o, count: counts.get(o.title) || o.count}));
console.log(res);
I need to filter some data inside an array of objects which is contained in another array of objects. Here is the sample structure of my data. I need to filter on categories.
[
{
id: 540,
name:'Makeup kit'
slug:'makeup-kit',
status:'publish',
categories: [
{
id: 42, name:'Fashion',slug:'fashion'
},
{
id: 43, name:'Beauty',slug:'beauty'
}
]
},
{
id: 541,
name:'Silicon gloves'
slug:'silicon-gloves',
status:'publish',
categories: [
{
id: 44, name:'Health',slug:'health'
}
]
},
{
id: 650,
name:'Julep Mask'
slug:'julep-mask',
status:'publish',
categories: [
{
id: 43, name:'Beauty',slug:'beauty'
}
]
}
]
Here is how I'm trying
beautyProducts=temp1.filter(product=>product.categories.filter(cat=>cat.id===43))
but my solution doesn't seem to work.
Array#filter() expects the function you give it to return a truthy or falsy value. Elements for which the function returns a truthy value are kept in the new array, and those that give a falsy value are removed.
You want to keep only elements for which one of the categories has an id of 43. Using a second filter, then, makes no sense here: it returns an array, and arrays are always truthy; therefore the first filter will always receive an array for each element and all elements are kept in the new array.
Instead of a second filter, you should use Array#some() - you want to know if any of the categories have id===43, and if none of them do, then you want a falsy value so that the product gets excluded from the results.
Simple change:
beautyProducts = temp1.filter(product => product.categories.some(cat => cat.id === 43))
Here is a working sample:
let temp1 = [{id:540,name:'Makeup kit',slug:'makeup-kit',status:'publish',categories:[{id:42,name:'Fashion',slug:'fashion'},{id:43,name:'Beauty',slug:'beauty'}]},{id:541,name:'Silicon gloves',slug:'silicon-gloves',status:'publish',categories:[{id:44,name:'Health',slug:'health'}]},{id:650,name:'Julep Mask',slug:'julep-mask',status:'publish',categories:[{id:43,name:'Beauty',slug:'beauty'}]}];
let beautyProducts = temp1.filter(product => product.categories.some(cat => cat.id === 43));
console.log(beautyProducts);
Try like this.
beautyProducts = temp1.map(({categories, ...others}) => {
const filteredCategories = categories.filter(cat => cat.id === 43);
return {
filteredCategories,
...others
};
}).filter(product => product.categories.length > 0)
So first, you should do the inner filter first and map the inner filtered data to the current one and do the main filter after that like above.
let data = [
{
id: 540,
name: 'Makeup kit',
slug: 'makeup-kit',
status: 'publish',
categories: [
{
id: 42, name: 'Fashion', slug: 'fashion'
},
{
id: 43, name: 'Beauty', slug: 'beauty'
}
]
},
{
id: 541,
name: 'Silicon gloves',
slug: 'silicon-gloves',
status: 'publish',
categories: [
{
id: 44, name: 'Health', slug: 'health'
}
]
},
{
id: 650,
name: 'Julep Mask',
slug: 'julep-mask',
status: 'publish',
categories: [
{
id: 43, name: 'Beauty', slug: 'beauty'
}
]
}
];
let beautyProducts = data.map(product => {
const categories = product.categories.filter(cat => cat.id === 43);
if (categories.length) {
return { ...product, categories };
}
return null;
}).filter(p => p);
console.log("Prod:", beautyProducts);
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>");
let beautyProductsTwo = data.filter(product => product.categories.some(cat => cat.id === 43));
console.log("Prod ans two:", beautyProductsTwo);