Problem with grouping array of objects in JS [duplicate] - javascript

This question already has answers here:
How to loop an object in React?
(8 answers)
Closed 1 year ago.
I have such array of objects:
[{id: 1, name: 'Apple', category: 'Fruit'}
{id: 2, name: 'Melon', category: 'Fruit'}
{id: 3, name: 'iPhone', category: 'Phone'}
{id: 4, name: 'Samsung Galaxy Note 8', category: 'Phone'}
{id: 5, name: 'Playstation 5', category: 'Entertainment'}]
and what I wanted to achieve is to combine product names by category and show them like:
Fruit
Apple
Melon
Phone
iPhone
Samsung Galaxy Note 8
Entertainment
Playstation 5
So, what I tried to achieve that is
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
const products = [{id: 1, name: 'Apple', category: 'Fruit'}
{id: 2, name: 'Melon', category: 'Fruit'}
{id: 3, name: 'iPhone', category: 'Phone'}
{id: 4, name: 'Samsung Galaxy Note 8', category: 'Phone'}
{id: 5, name: 'Playstation 5', category: 'Entertainment'}]
console.log(groupBy([products], 'category'));

You have to adjust your reduce a bit:
const mapping = arr.reduce((obj, entry) => {
obj[entry.category] = obj[entry.category] ? [...obj[entry.category], entry] : [entry]
return obj;
}, {})
resulting in
{
Entertainment: [{
category: "Entertainment",
id: 5,
name: "Playstation 5"
}],
Fruit: [{
category: "Fruit",
id: 1,
name: "Apple"
}, {
category: "Fruit",
id: 2,
name: "Melon"
}],
Phone: [{
category: "Phone",
id: 3,
name: "iPhone"
}, {
category: "Phone",
id: 4,
name: "Samsung Galaxy Note 8"
}]
}
And you can adjust what you want to save by changing entry to a desired value of entry.

I would approach your groupBy method like this:
function groupBy(data, key, value) {
const groups = {};
data.forEach(element => {
let subkey = element[key];
if (!(subkey in groups)) {
groups[subkey] = [element[value]];
} else {
groups[subkey].push(element[value]);
}
});
return groups;
}
console.log(groupBy(products, "category", "name")
You loop over every element, and if the specified key is not already in the groups object it will be added. if it's already added we just add the new element to the array.
This is an example return value of the groupBy function:
{
Fruit: [ 'Apple', 'Melon' ],
Phone: [ 'iPhone', 'Samsung Galaxy Note 8' ],
Entertainment: [ 'Playstation 5' ]
}

To generate HTML code
var groupBy = function(xs, key) {
return xs.reduce(function(rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
const products = [{id: 1, name: 'Apple', category: 'Fruit'},
{id: 2, name: 'Melon', category: 'Fruit'},
{id: 3, name: 'iPhone', category: 'Phone'},
{id: 4, name: 'Samsung Galaxy Note 8', category: 'Phone'},
{id: 5, name: 'Playstation 5', category: 'Entertainment'}];
const groups = groupBy(products, 'category');
const html = Object.keys(groups).reduce((code, cat) => {
const inner = groups[cat].reduce((i, product) => {
return i + `<p>${product.name}</p>`;
}, '');
return code + `<div><h2>${cat}</h2>${inner}</div>`;
}, '');
document.getElementById('container').innerHTML = html;
p { margin-left: 20px; }
<div id="container"></div>

var groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
const arrayData = [
{ id: 1, name: 'Apple', category: 'Fruit' },
{ id: 2, name: 'Melon', category: 'Fruit' },
{ id: 3, name: 'iPhone', category: 'Phone' },
{ id: 4, name: 'Samsung Galaxy Note 8', category: 'Phone' },
{ id: 5, name: 'Playstation 5', category: 'Entertainment' }
]
console.log(groupBy(arrayData, 'category'));
result:
{
"Fruit": [
{
"id": 1,
"name": "Apple",
"category": "Fruit"
},
{
"id": 2,
"name": "Melon",
"category": "Fruit"
}
],
"Phone": [
{
"id": 3,
"name": "iPhone",
"category": "Phone"
},
{
"id": 4,
"name": "Samsung Galaxy Note 8",
"category": "Phone"
}
],
"Entertainment": [
{
"id": 5,
"name": "Playstation 5",
"category": "Entertainment"
}
]
}

Related

How to create a nested array of object from an array of objects

How Can I loop through this array of objects and change it so that the individual menu items are nested in the object menu_name?
const menus = [
{ menu_name: 'Entre', id:0 },
{
name: 'Soup',
price: 14.99,
id:1
},
{
name: 'Chips & Salsa',
price: 7.99,
id:2
},
{
name: 'Chicken Nuggets',
price: 12.99,
id:3
},
{ menu_name: 'Sides', id:4 },
{
name: 'Fries',
price: 4.99,
id:5
},
{
name: 'Drinks',
price: 2.99,
id:6
},
{
name: 'Onion Rings',
price: 5.99,
id:7
},
];
the end result should look like this for each menu_name object, where an array of menus is nested in the menu_name object
{
menu_name: 'Sides',
menu: [
{
name: 'Fries',
price: 4.99,
},
{
name: 'Drinks',
price: 2.99,
},
{
name: 'Onion Rings',
price: 5.99,
},
],
},
You can easily achieve this using reduce and object destructuring
const menus = [
{ menu_name: "Entre", id: 0 },
{
name: "Soup",
price: 14.99,
id: 1,
},
{
name: "Chips & Salsa",
price: 7.99,
id: 2,
},
{
name: "Chicken Nuggets",
price: 12.99,
id: 3,
},
{ menu_name: "Sides", id: 4 },
{
name: "Fries",
price: 4.99,
id: 5,
},
{
name: "Drinks",
price: 2.99,
id: 6,
},
{
name: "Onion Rings",
price: 5.99,
id: 7,
},
];
const result = menus.reduce((acc, curr) => {
const { menu_name } = curr;
if (menu_name) {
acc.push({ menu_name, menu: [] });
} else {
const { name, price } = curr;
acc[acc.length - 1].menu.push({ name, price });
}
return acc;
}, []);
console.log(result);
var newMenu = [];
menus.forEach(menu=>{
if(menu.menu_name){
newMenu.push({...menu, menu: []})
}else{
newMenu[newMenu.length-1].menu.push(menu)
}
});

How to first combine properties of an object then remove the duplicates in an array of objects using Javascript

I have an array of objects here:
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test2", quantity:1 },
{ id: 2, name: "test3", quantity:1 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:1 },
{ id: 5, name: "test7", quantity:1 },
{ id: 6, name: "test8", quantity:1 }
];
I want to add quantities of the duplicate objects together before removing them
So the result is:
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test3", quantity:2 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:2 },
{ id: 6, name: "test8", quantity:1 }
];
I have seen variations of it done removing duplicates using map or reduce but I haven't seen anything that can what I want to accomplish in an eloquent way without using too many loops.
I have been thinking about how to best accomplish this all day and haven't found anything, any help would be appreciated
You can use reduce with an object to store the element with each id.
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test2", quantity:1 },
{ id: 2, name: "test3", quantity:1 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:1 },
{ id: 5, name: "test7", quantity:1 },
{ id: 6, name: "test8", quantity:1 }
];
const res = Object.values(
arr.reduce((acc,curr)=>{
acc[curr.id] = acc[curr.id] || {...curr, quantity: 0};
acc[curr.id].quantity += curr.quantity;
return acc;
}, {})
);
console.log(res);
const arr = [
{ id: 1, name: "test1", quantity: 1 },
{ id: 2, name: "test2", quantity: 1 },
{ id: 2, name: "test3", quantity: 1 },
{ id: 3, name: "test4", quantity: 1 },
{ id: 4, name: "test5", quantity: 1 },
{ id: 5, name: "test6", quantity: 1 },
{ id: 5, name: "test7", quantity: 1 },
{ id: 6, name: "test8", quantity: 1 }
];
var result = arr.reduce(function (r, a) {
r[a.id] = r[a.id] || { id: a.id, quantity: 0, name: a.name };
r[a.id].quantity += a.quantity;
return r;
}, Object.create(null));
console.log(JSON.stringify(result));
Using forEach loop and build object with aggregated quantity count.
const convert = (arr) => {
const res = {};
arr.forEach(({ id, ...rest }) =>
res[id] ? (res[id].quantity += 1) : (res[id] = { id, ...rest })
);
return Object.values(res);
};
const arr = [
{ id: 1, name: "test1", quantity: 1 },
{ id: 2, name: "test2", quantity: 1 },
{ id: 2, name: "test3", quantity: 1 },
{ id: 3, name: "test4", quantity: 1 },
{ id: 4, name: "test5", quantity: 1 },
{ id: 5, name: "test6", quantity: 1 },
{ id: 5, name: "test7", quantity: 1 },
{ id: 6, name: "test8", quantity: 1 },
];
console.log(convert(arr));

How do i filter an array inside of a array of objects value [duplicate]

This question already has an answer here:
How do I filter an array of object containing an array of object itself?
(1 answer)
Closed 2 years ago.
const data = [
{ name: "name1", option: "option1", category: [{ id: 1, value: "national" }] },
{ name: "name2", option: "option2", category: [{ id: 2, value: "international" }] },
{ name: "name3", option: "option3", category: [{ id: 3, value: "sports" }] },
{ name: "name4", option: "option4", category: [{ id: 4, value: "entertainment" }] },
];
I would like to filter of this array value of category
// // console.log(data);
const result = data.filter(e => {
return e.category.filter(b => b.value === 'national')
})
// I want output like bellow
{ name: "name1", option: "option1", category: [{ id: 1, value: "national" }] },
I modify the code for multiple arrays in category:
const data = [
{ name: "name1", option: "option1", category: [{ id: 1, value: "national" }, {id: 1, value: "mundial" }]},
{ name: "name2", option: "option2", category: [{ id: 2, value: "international" }] },
{ name: "name3", option: "option3", category: [{ id: 3, value: "sports" }] },
{ name: "name4", option: "option4", category: [{ id: 4, value: "entertainment" }] },
];
var result = data.filter(x => x.category.some(y => y.value == "mundial"));
console.log(result);

Count duplicates and order them in array of objects Javascript

I have the following array of objects:
[
{
id: 1,
someOtherStuff: 'abc,
Drink: { name: 'Coca-Cola', price: 2.5 }
},
{
id: 2,
someOtherStuff: 'def,
Drink: { name: 'Fanta Orange', price: 3 }
},
{
id: 3,
someOtherStuff: 'ghi,
Drink: { name: 'Sprite', price: 1.8 }
},
{
id: 6,
someOtherStuff: 'jkl,
Drink: { name: 'Coca-Cola', price: 2.5 }
},
{
id: 7,
someOtherStuff: 'mno,
Drink: { name: 'Coca-Cola', price: 2.5 }
}
]
i want to group them by duplicates like this:
[
{
count: 3,
drinkName: 'Coca-Cola',
price: 2.5
},
{
count: 1,
drinkName: 'Fanta Orange',
price: 3
},
{
count: 1,
drinkName: 'Sprite',
price: 1.8
}
]
I have tried in several ways to map a new array.But unfortunately I can't get it to work
I hope someone can help me with that
let result= {};
inputArray.map((item)=>{
let key = `${item.Drink.name}-${item.Drink.price}`;
if(result[key]){
result[key].count = result[key].count +1;
}else{
result[key] = {count:1,drinkName:item.Drink.name,price:item.Drink.price};
}
});
result = Object.values(result);

Using nested reduces on an object by properties

I have data like this:
const data = [
{ id: 1, cat: "human", age: "10" },
{ id: 2, cat: "human", age: "20" },
{ id: 3, cat: "human", age: "10" },
{ id: 4, cat: "animal", age: "10" },
{ id: 5, cat: "animal", age: "20" },
{ id: 6, cat: "animal", age: "10" },
{ id: 7, cat: "alien", age: "10" },
{ id: 8, cat: "alien", age: "20" },
{ id: 9, cat: "alien", age: "10" },
];
I want to group this data something like that:
const gr = {
human: {
all: [
{ id: 1, cat: "human", age: "10" },
{ id: 2, cat: "human", age: "20" },
{ id: 3, cat: "human", age: "10" },
],
ages: {
"10": [
{ id: 1, cat: "human", age: "10" },
{ id: 3, cat: "human", age: "10" },
],
"20": [
{ id: 2, cat: "human", age: "20" },
],
}
},
animal: {...},
alien: {...},
}
I do first reduce like that:
const gr = data.reduce((acc, el) => {
const { cat } = el;
acc[cat] = acc[cat] || { all: [] };
acc[cat].all.push(el);
return acc;
}, {});
But I can't make a nested reduce here. I can do it separately like that:
const grAge = gr.human.all.reduce((acc,el) => {
const {age} = el;
acc[age] = acc[age] || [];
acc[age].push(el);
return acc;
},{});
gr.human["ages"] = grAge;
But obviously, this is not so efficient and needs more work. Maybe like this:
Object.keys(gr).forEach(key => {
const grAge = gr[key].all.reduce((acc,el) => {
const {age} = el;
acc[age] = acc[age] || [];
acc[age].push(el);
return acc;
},{});
gr[key]["ages"] = grAge;
});
Can I join those reduces in a single step?
If there are any other good methods I can use them, I don't need to use the reduce method.
You could take a sinle loop approach and assign the wanted structure to either allor to a nested strcture.
If you like to get a more dynamic version, you need to simplify the result structure for every nesting level (this means, the age level would contain an all property).
const
data = [{ id: 1, cat: "human", age: "10" }, { id: 2, cat: "human", age: "20" }, { id: 3, cat: "human", age: "10" }, { id: 4, cat: "animal", age: "10" }, { id: 5, cat: "animal", age: "20" }, { id: 6, cat: "animal", age: "10" }, { id: 7, cat: "alien", age: "10" }, { id: 8, cat: "alien", age: "20" }, { id: 9, cat: "alien", age: "10" }],
result = data.reduce((r, o) => {
r[o.cat] = r[o.cat] || { all: [], ages: {} };
r[o.cat].all.push(o);
r[o.cat].ages[o.age] = r[o.cat].ages[o.age] || [];
r[o.cat].ages[o.age].push(o);
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another way to do this would be to get every unique category and ages using Sets, and then reducing them into your final JSON :
EDIT : It seems like the Stack Overflow snippet doesn't like it, but executing it in your browser console will give out the correct result
const data = [
{ id: 1, cat: "human", age: "10" },
{ id: 2, cat: "human", age: "20" },
{ id: 3, cat: "human", age: "10" },
{ id: 4, cat: "animal", age: "10" },
{ id: 5, cat: "animal", age: "20" },
{ id: 6, cat: "animal", age: "10" },
{ id: 7, cat: "alien", age: "10" },
{ id: 8, cat: "alien", age: "20" },
{ id: 9, cat: "alien", age: "10" },
];
const output = [...new Set(data.map(thing => thing.cat))].reduce((acc, category) => {
const catData = data.filter(thing => thing.cat === category)
return {
[category]: {
all: catData,
ages : [...new Set(catData.map(catThing => catThing.age))].reduce((catAcc, age) => ({
[age]: [...catData.filter(catThing => catThing.age === age)],
...catAcc
}), {})
},
...acc
}
}, {})
console.log(output)
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories