Is it possible to reduce the number of for loops to just one in this case? I need to group an object based on 'grade' property, no matter the data type of the output, even doesn't matter if your solution force me to start over again. I don't know much about algorithms for now so I need your help to improve my code because I am not allowed to use more than one for loop in a single block of code.
var schools = {
'SCHOOL_1':
[
// girls
{id: '1', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'},
{id: '2', school: 'SCHOOL_1', grade: 'A', message: 'Good work!'},
{id: '3', school: 'SCHOOL_1', grade: 'A', message: 'Ok'},
// boys
{id: '4', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'},
{id: '5', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'},
{id: '6', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'},
{id: '7', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'},
{id: '8', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'},
],
'SCHOOL_2':
[
// girls
{id: '9', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '10', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '11', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '12', school: 'SCHOOL_2', grade: 'B', message: 'Good work!'},
{id: '13', school: 'SCHOOL_2', grade: 'B', message: 'Nice!'},
// boys
{id: '14', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '15', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '16', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '17', school: 'SCHOOL_2', grade: 'B', message: 'Congratulations!'},
]
}
var result = [];
for (let school in schools) {
// Group students by grade
let studentsByGrade = GroupByProperty(schools[school], 'grade');
// Second loop (I NEED TE REFACTOR THIS)
for (let grade in studentsByGrade) {
if (!result[grade]) result[grade] = [];
result[grade].push(studentsByGrade[grade]);
}
}
console.log('result',result);
function GroupByProperty(objectArray, property) {
let result = objectArray.reduce((acc, obj) => {
var key = obj[property];
if (!acc[key]) acc[key] = [];
acc[key].push(obj);
return acc;
}, {});
return result;
}
2 Answers 2
By combining Object.values and Array.prototype.flat, you can turn this object into a single list of objects.
This would do it:
function GroupByProperty(objectArray, property) {
let result = objectArray.reduce((acc, obj) => {
var key = obj[property];
if (!acc[key]) acc[key] = [];
acc[key].push(obj);
return acc;
}, {});
return result;
}
const byGrades = (schools) =>
GroupByProperty (Object .values (schools) .flat(), 'grade')
var schools = {'SCHOOL_1': [{id: '1', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'}, {id: '2', school: 'SCHOOL_1', grade: 'A', message: 'Good work!'}, {id: '3', school: 'SCHOOL_1', grade: 'A', message: 'Ok'}, {id: '4', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'}, {id: '5', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'}, {id: '6', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'}, {id: '7', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'}, {id: '8', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'}], 'SCHOOL_2': [{id: '9', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'}, {id: '10', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'}, {id: '11', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'}, {id: '12', school: 'SCHOOL_2', grade: 'B', message: 'Good work!'}, {id: '13', school: 'SCHOOL_2', grade: 'B', message: 'Nice!'}, {id: '14', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'}, {id: '15', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'}, {id: '16', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'}, {id: '17', school: 'SCHOOL_2', grade: 'B', message: 'Congratulations!'}]}
console .log (byGrades (schools))
Comments
Compact solution using Object.values() flat() and reduce() implemented with destructuring and making use of the nullish coalescing operator.
const bygrade = Object.values(schools)
.flat()
.reduce((acc, o) =>
(acc[o.grade] = [...acc[o.grade] ?? [], {...o}], acc), {});
var schools = {
'SCHOOL_1':
[
// girls
{id: '1', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'},
{id: '2', school: 'SCHOOL_1', grade: 'A', message: 'Good work!'},
{id: '3', school: 'SCHOOL_1', grade: 'A', message: 'Ok'},
// boys
{id: '4', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'},
{id: '5', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'},
{id: '6', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'},
{id: '7', school: 'SCHOOL_1', grade: 'A', message: 'Congratulations!'},
{id: '8', school: 'SCHOOL_1', grade: 'B', message: 'Good work!'},
],
'SCHOOL_2':
[
// girls
{id: '9', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '10', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '11', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '12', school: 'SCHOOL_2', grade: 'B', message: 'Good work!'},
{id: '13', school: 'SCHOOL_2', grade: 'B', message: 'Nice!'},
// boys
{id: '14', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '15', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '16', school: 'SCHOOL_2', grade: 'A', message: 'Congratulations!'},
{id: '17', school: 'SCHOOL_2', grade: 'B', message: 'Congratulations!'},
]
}
const bygrade = Object.values(schools).flat().reduce((acc, o) => (acc[o.grade] = [...acc[o.grade] ?? [], {...o}], acc), {});
console.log(bygrade);
1 Comment
reduce call in the question (GroupByProperty).
Object.values(schools).flat()