Ryan Callens
Ryan Callens

Reputation: 43

Javascript: More concise way to reduce/aggregate by key?

This code gives the expected result, but is there a more concise way to achieve the same result? This is simply a matter of curiosity though.

The goal is to have a map representing the total students in each school, as well as a map representing the total teachers in each school.

// Example data
const studentsMap = {
    student123: {
        teacher: 'teacher123'
    },
    student456: {
        teacher: 'teacher123'
    },
    student789: {
        teacher: 'badID'
    },
    student000: {}
};
const teachersMap = {
    teacher123: {
        school: 'school123'
    },
    teacher456: {
        school: 'school123'
    },
    teacher789: {
        school: 'school456'
    }
};

const studentsTotalBySchool = Object.keys(studentsMap).reduce((totals, key) => {
    const current = studentsMap[key];
    if (!teachersMap[current.teacher] || !teachersMap[current.teacher].school) {
        return totals;
    }
    totals[teachersMap[current.teacher].school] = (totals[teachersMap[current.teacher].school] || 0) + 1;
    return totals;
}, {});

const teachersTotalBySchool = Object.keys(teachersMap).reduce((totals, key) => {
    const current = teachersMap[key];
    totals[current.school] = (totals[current.school] || 0) + 1;
    return totals;
}, {});

Is there a way to write this more succinctly without sacrificing too much readability?

Upvotes: 1

Views: 139

Answers (2)

Bahaaaldin Mohammad
Bahaaaldin Mohammad

Reputation: 117

this will get you the same results with much less code

 let schools = {
  school123: {
    teacher123 : {
      students: ["student123", "student456"]
    },
    teacher456 : {
      students: ["student789"]
    }
  },
  school456: {
    teacher123 : {
      students: ["student123", "student456"]
    },
    teacher456 : {
      students: ["student789"]
    }
  }
};

function findTotal(school, totalOf){

  let accumulated = 0;

  switch(totalOf){

    case "students":
      for(let teachers of Object.keys(schools[school])){
        accumulated += schools[school][teachers].students.length;
      }
      break;

    case "teachers":
    accumulated = Object.keys(schools[school]).length;

  }

  return accumulated;

}
console.log(findTotal("school123", "students"))
console.log(findTotal("school123", "teachers"))

Upvotes: 0

Jack Bashford
Jack Bashford

Reputation: 44105

You can use Object.entries and destructuring like so:

const studentsTotalBySchool = Object.entries(studentsMap).reduce((totals, [key, { teacher }) => {
    if (!teachersMap[teacher] || !teachersMap[teacher].school) return totals;
    totals[teachersMap[teacher].school] = (totals[teachersMap[teacher].school] || 0) + 1;
    return totals;
}, {});

const teachersTotalBySchool = Object.entries(teachersMap).reduce((totals, [key, { school }) => {
    totals[school] = (totals[school] || 0) + 1;
    return totals;
}, {});

Upvotes: 2

Related Questions