Reputation: 171
I am trying to turn an array of objects into another array of objects by grouping by a specific value and adding that value as label and taking it out of the object in the new array.
Input: So for instance I have this array of objects:
let tech = [
{ id: 1, grouping: "Front End", value: "HTML" },
{ id: 2, grouping: "Front End", value: "React" },
{ id: 3, grouping: "Back End", value: "Node" },
{ id: 4, grouping: "Back End", value: "PHP" },
];
Expected: I am looking to try and figure out how I can get to this, where there is a label for each of the unique groupings and options array containing the values of that grouping.
[
{
label: "Front End",
options: [
{ id: 1, value: "HTML" },
{ id: 2, value: "React" },
],
},
{
label: "Back End",
options: [
{ id: 3, value: "Node" },
{ id: 4, value: "PHP" },
],
},
]
The closest I have been able to get to is using reduce to group by the grouping key:
const groupedTech = tech.reduce((acc, value) => {
// Group initialization
if (!acc[value.grouping]) {
acc[value.grouping] = [];
}
// Grouping
acc[value.grouping].push(value);
return acc;
}, {});
Which gives me this:
{
"Front End": [
{ id: 1, grouping: "Front End", value: "HTML" },
{ id: 2, grouping: "Front End", value: "React" },
],
"Back End": [
{ id: 3, grouping: "Back End", value: "Node" },
{ id: 4, grouping: "Back End", value: "PHP" },
],
}
But this returns object not an array and doesn't remove the grouping value. I have not been able to figure out how to group properly because in the array of objects I have not found an efficient way to compare against to see if the grouping exists and if so add to that nested array. Would I be better off using something like .map()? Appreciate any leads/learnings!
Upvotes: 13
Views: 12000
Reputation: 89284
We can make use of Object.groupBy
as the first step to aggregate the objects by the grouping
key for a much simplified solution.
const tech = [
{ id: 1, grouping: "Front End", value: "HTML" },
{ id: 2, grouping: "Front End", value: "React" },
{ id: 3, grouping: "Back End", value: "Node" },
{ id: 4, grouping: "Back End", value: "PHP" },
];
const res = Object.entries(Object.groupBy(tech, o => o.grouping))
.map(([label, v]) => ({label, options:
v.map(({grouping, ...rest}) => rest)}));
console.log(res);
Upvotes: 1
Reputation: 1
const inventory = [
{ name: "asparagus", type: "vegetables", quantity: 5 },
{ name: "bananas", type: "fruit", quantity: 10 },
{ name: "goat", type: "meat", quantity: 40 },
{ name: "cherries", type: "fruit", quantity: 5 },
{ name: "fish", type: "meat", quantity: 22 },
{ name: "fish", type: "cereals", quantity: 100 },
{ name: "fish", type: "meat", quantity: 20 },
{ name: "fish", type: "cereals", quantity: 12 },
];
function func(inventory){
let type = [], result = {};
inventory.map((item)=>{type.push(item.type)})
type = [...new Set(type)]
for(i=0;i<inventory.length;i++){
if(type.find(item => item === inventory[i].type)){
result= {
...result,
[inventory[i].type]:
result[type.find(item => item === inventory[i].type)] ?
result[type.find(item => item === inventory[i].type)] +inventory[i].quantity
: inventory[i].quantity
}
}
}
return result
}
console.log(func(inventory))
Upvotes: 0
Reputation: 171669
Using a Map and Map#values()
const grouped = tech.reduce((m,{grouping:label, ...rest})=>{
const group = m.get(label) || {label, options:[]};
group.options.push({...rest})
return m.set(label, group)
},new Map)
console.log([...grouped.values()])
<script>
let tech=[{id:1,grouping:"Front End",value:"HTML"},{id:2,grouping:"Front End",value:"React"},{id:3,grouping:"Back End",value:"Node"},{id:4,grouping:"Back End",value:"PHP"}];
</script>
Upvotes: 2
Reputation: 20699
You're very close, just wrap the key-value entries of the result you've got in a map
function:
let tech = [
{ id: 1, grouping: "Front End", value: "HTML" },
{ id: 2, grouping: "Front End", value: "React" },
{ id: 3, grouping: "Back End", value: "Node" },
{ id: 4, grouping: "Back End", value: "PHP" },
];
const groupedTech = Object.entries(
// What you have done
tech.reduce((acc, { id, grouping, value }) => {
// Group initialization
if (!acc[grouping]) {
acc[grouping] = [];
}
// Grouping
// FIX: only pushing the object that contains id and value
acc[grouping].push({ id, value });
return acc;
}, {})
).map(([label, options]) => ({ label, options }));
console.log(groupedTech);
Upvotes: 11
Reputation: 164798
I usually like to build up a Map
of key / value pairs then transform those entries into the final result (usually using Array.prototype.map()
or Array.from()
).
const tech = [
{ id: 1, grouping: "Front End", value: "HTML" },
{ id: 2, grouping: "Front End", value: "React" },
{ id: 3, grouping: "Back End", value: "Node" },
{ id: 4, grouping: "Back End", value: "PHP" },
];
const groupedMap = tech.reduce((map, { grouping, ...option }) => {
if (!map.has(grouping)) {
map.set(grouping, [])
}
map.get(grouping).push(option)
return map
}, new Map())
const groupedTech = Array.from(groupedMap, ([ label, options ]) => ({
label,
options
}))
console.log(groupedTech)
Upvotes: 2
Reputation: 147166
A minor variation on the other two answers if you want to get exactly the output you specify:
let tech = [{
id: 1,
grouping: "Front End",
value: "HTML"
},
{
id: 2,
grouping: "Front End",
value: "React"
},
{
id: 3,
grouping: "Back End",
value: "Node"
},
{
id: 4,
grouping: "Back End",
value: "PHP"
},
];
const groupedTech = Object.entries(
tech.reduce((acc, value) => {
// Group initialization
if (!acc[value.grouping]) {
acc[value.grouping] = [];
}
// Grouping
acc[value.grouping].push({
id: acc[value.grouping].length+1,
value: value.value
});
return acc;
}, {}))
.map(([label, options]) => ({
label,
options
}));
console.log(groupedTech);
Upvotes: 2
Reputation: 14891
You just have to do one more manipulation with Object.entries
and .map
let tech = [
{ id: 1, grouping: 'Front End', value: 'HTML' },
{ id: 2, grouping: 'Front End', value: 'React' },
{ id: 3, grouping: 'Back End', value: 'Node' },
{ id: 4, grouping: 'Back End', value: 'PHP' }
]
const groupedTech = tech.reduce((acc, value) => {
// Group initialization
if (!acc[value.grouping]) {
acc[value.grouping] = []
}
// Grouping
acc[value.grouping].push(value)
return acc
}, {})
const res = Object.entries(groupedTech).map(([label, options]) => ({
label,
options
}))
console.log(res)
Upvotes: 2