I have an array of objects like this:
[
{
"id": 1,
"name": "Question1",
"categories": [
{
"id": 20,
"name": "Science"
},
{
"id": 21,
"name": "General Knowledge"
},
{
"id": 20,
"name": "Mathematic"
}
]
},
{
"id": 2,
"name": "Question2",
"categories": [
{
"id": 20,
"name": "Science"
}
]
},
{
"id": 3,
"name": "Question3",
"categories": [
{
"id": 20,
"name": "Science"
}
]
}
]
and I want to group the objects into sub-arrays (Sorted alphabetically) by the object property name of the array categories.
The expected output would be:
[
//General Knowledge
[
{
"id": 1,
"name": "Question1",
"categories": [
{
"id": 20,
"name": "Science"
},
{
"id": 21,
"name": "General Knowledge"
},
{
"id": 20,
"name": "Mathematic"
}
]
}
],
//Mathematic
[
{
"id": 1,
"name": "Question1",
"categories": [
{
"id": 20,
"name": "Science"
},
{
"id": 21,
"name": "General Knowledge"
},
{
"id": 20,
"name": "Mathematic"
}
]
}
],
//Science
[
{
"id": 1,
"name": "Question1",
"categories": [
{
"id": 20,
"name": "Science"
},
{
"id": 21,
"name": "General Knowledge"
},
{
"id": 20,
"name": "Mathematic"
}
]
},
{
"id": 2,
"name": "Question2",
"categories": [
{
"id": 20,
"name": "Science"
}
]
},
{
"id": 3,
"name": "Question3",
"categories": [
{
"id": 20,
"name": "Science"
}
]
}
]
]
I've been trying using loops and Array.reduce()
, but I didn't manage to get it working.
Which one would be the most performant way to achieve the expected output? Many thanks!
CodePudding user response:
Loop through each object and inside that loop through the categories
. Use each category name as the key and an array of questions as value in the group
object
const group = {}
for (const q of questions) {
for(const c of q.categories) {
group[c.name] ??= []
group[c.name].push(q)
}
}
const output = Object.values(group)
Here's a snippet:
const questions =[{id:1,name:"Question1",categories:[{id:20,name:"Science"},{id:21,name:"General Knowledge"},{id:20,name:"Mathematic"}]},{id:2,name:"Question2",categories:[{id:20,name:"Science"}]},{id:3,name:"Question3",categories:[{id:20,name:"Science"}]}];
const group = {}
for (const q of questions) {
for(const c of q.categories) {
group[c.name] ??= []
group[c.name].push(q)
}
}
const output = Object.values(group)
document.querySelector("pre").innerText = JSON.stringify(output, null, 4)
<pre />
CodePudding user response:
Assuming your expected output is correct, this is what I've done. I don't know that this is the most performant way to do it, but it works:
const input = [
{
id: 1,
name: "Question1",
categories: [
{
id: 20,
name: "Science",
},
{
id: 21,
name: "General Knowledge",
},
{
id: 20,
name: "Mathematic",
},
],
},
{
id: 2,
name: "Question2",
categories: [
{
id: 20,
name: "Science",
},
],
},
{
id: 3,
name: "Question3",
categories: [
{
id: 20,
name: "Science",
},
],
},
];
// First we put all subjects into an array.
const subjects = [];
for (const element of input) {
for (const categories of element.categories) {
if (!subjects.find((e) => e === categories.name)) {
subjects.push(categories.name);
}
}
}
// then we add the element to our output ordered by subjet
const output = [];
for (const subject of subjects) {
const tempOutput = [];
for (const element of input) {
if (element.categories?.find((e) => e.name === subject)) {
tempOutput.push(element);
}
}
output.push(tempOutput);
}
console.log(output);