0

I've been stuck on this for a while. Thanks for any help!

I have these two JavaScript (es6) arrays:

const examListArray = [
  {examId: 'eee1', examName: 'Qtr 1 Exam'},
  {examId: 'eee2', examName: 'Qtr 2 Exam'},
  {examId: 'eee3', examName: 'Qtr 3 Exam'},
  {examId: 'eee4', examName: 'Final Exam'},
]

const examScoresArray = [

  {resultId: 'rrr01', examId: 'eee1', studentId: 'sss1', grade: 78},
  {resultId: 'rrr02', examId: 'eee1', studentId: 'sss2', grade: 82},
  {resultId: 'rrr03', examId: 'eee1', studentId: 'sss3', grade: 93},
  {resultId: 'rrr04', examId: 'eee1', studentId: 'sss4', grade: 85},
  {resultId: 'rrr05', examId: 'eee1', studentId: 'sss5', grade: 78},
  {resultId: 'rrr06', examId: 'eee1', studentId: 'sss6', grade: 84},
  {resultId: 'rrr07', examId: 'eee2', studentId: 'sss1', grade: 89},
  {resultId: 'rrr08', examId: 'eee2', studentId: 'sss2', grade: 88},
  {resultId: 'rrr09', examId: 'eee2', studentId: 'sss3', grade: 81},
  {resultId: 'rrr10', examId: 'eee2', studentId: 'sss4', grade: 95},

]

Here's the reduce function that I have so far, but need help with the Min, Max, and Avg parts, the examCount works perfectly.

const reducedExams = (list, scores) => {

  const countReducer = (scores, currentId) => {
    const countNum = scores.reduce((result, current) => {
      const foundAMatch = currentId === current.examId

      if (foundAMatch) {
        result++;
      }
      return result;
    }, 0);

    return countNum
  }

  const minScoreReducer = (scores, currentId) => {
     /*Need Help Here Please!*/
  }

  const maxScoreReducer = (scores, currentId) => {
     /*Need Help Here Please!*/
  }

  const avgScoreReducer = (scores, currentId) => {
     /*Need Help Here Please!*/
  }

  const resultData = list.reduce((result, current) => {

    const currentId = current.examId

    const examCount = countReducer(scores, currentId)
    const minScore = minScoreReducer(scores, currentId)
    const maxScore = maxScoreReducer(scores, currentId)
    const avgScore = avgScoreReducer(scores, currentId)

    return {
      ...result,
      [current.examName]: {
        ...result[current],
        examCount,
        minScore,
        maxScore,
        avgScore,

      }
    }

  }, {})

  return resultData

}

const examListTable = reducedExams(examListArray, examScoresArray)

console.log('exam table output', examListTable)

What I'm trying to do is is loop through my Exams List and make a table that will show something like this.

_____________Count____Min____Max___Avg

Qtr 1 Exam:____6______78_____93___83.333

Qtr 2 Exam:____4______81_____95___88.25

Qtr 3 Exam:____0______0_____0_____0

Final Exam:____0______0_____0_____0

Any help would be greatly appreciated!

And one last thing... if I'm going about this all wrong, ie, unnecessarily using reduce instead of some type of loop, Please by all means, I'm open to any suggestions. This feels very messy.

My stack: React, Redux, Firebase/FireStore

I always upvote! btw Thanks again!

5
  • You should start by making an attempt to write some code for those 3 functions... Commented Jul 31, 2018 at 1:05
  • I've spent a couple days writing much code for those 3 functions. Can't figure it out which is why I'm here. Thanks! Commented Jul 31, 2018 at 1:08
  • From what you've posted, it doesn't look like you've made any attempt to write code for those yet. Please show your attempt and explain where you've gotten stuck. Commented Jul 31, 2018 at 1:09
  • 2
    I would agree with @CertainPerformance, this seems less a question, and more of a "please do this for me." Commented Jul 31, 2018 at 1:13
  • @CertainPerformance and @clint I admit I haven't the slightest clue how to proceed from what I've posted. I've been trying to solve it for about two days now. I'm getting the feeling like I'm going about the solution all wrong, like reduce() isn't what i need but a for loop or something. I'm totally clueless here. Any help at all would be greatly appreciated!! Commented Jul 31, 2018 at 1:57

2 Answers 2

1

You can use the array method filter to get the target you want and process.

const reducedExams = (list, scores) => {

  const countReducer = (scores, currentId) => {
    const matchedScores = scores.filter(score => score.examId === currentId);
    return matchedScores.length;
  }

  const minScoreReducer = (scores, currentId) => {
    const count = scores.filter(score => score.examId === currentId)
                        .reduce((min, score) => {
                          return score.grade < min ? score.grade : min;
                        }, Number.MAX_VALUE);
    if (count === Number.MAX_VALUE) {
      return 0;
    }
    return count;
  }

  const maxScoreReducer = (scores, currentId) => {
    const count = scores.filter(score => score.examId === currentId)
                        .reduce((max, score) => {
                          return score.grade > max ? score.grade : max;
                        }, Number.MIN_VALUE);
    if (count === Number.MIN_VALUE) {
      return 0;
    }
    return count;
  }

  const avgScoreReducer = (scores, currentId) => {
    let num = 0;
    const total = scores.filter(score => score.examId === currentId)
                      .reduce((sum, score) => {
                        num++;
                        sum += score.grade;
                        return sum;
                      }, 0);
    if (num === 0) {
      return 0;
    }

    return total / num;
  }

  const resultData = list.reduce((result, current) => {

    const currentId = current.examId
    const examCount = countReducer(scores, currentId)
    const minScore = minScoreReducer(scores, currentId)
    const maxScore = maxScoreReducer(scores, currentId)
    const avgScore = avgScoreReducer(scores, currentId)

    return {
      ...result,
      [current.examName]: {
        ...result[current],
        examCount,
        minScore,
        maxScore,
        avgScore,

      }
    }

  }, {})

  return resultData;

}

const examListTable = reducedExams(examListArray, examScoresArray)

console.log('exam table output', examListTable)
Sign up to request clarification or add additional context in comments.

1 Comment

Brilliant!! Exactly what I have been needing! THANK YOU @Anthony Liu (Since your solution most closely fits with my coding style, your suggestion gets the "solved" check mark) Thanks again!! You're a life saver!
1

The trick to solving these problems is breaking them down into smaller objectives.

The first objective being to categorise scores by exam and the second being to derive metrics.

Arrays can typically be categorised into object form using reduce().

Math is often useful for simple processes such as finding min / max values.

See below for a practical example.

// Input.
const exams = [{examId: 'eee1', examName: 'Qtr 1 Exam'},{examId: 'eee2', examName: 'Qtr 2 Exam'},{examId: 'eee3', examName: 'Qtr 3 Exam'},{examId: 'eee4', examName: 'Final Exam'}]
const scores = [{resultId: 'rrr01', examId: 'eee1', studentId: 'sss1', grade: 78},{resultId: 'rrr02', examId: 'eee1', studentId: 'sss2', grade: 82},{resultId: 'rrr03', examId: 'eee1', studentId: 'sss3', grade: 93},{resultId: 'rrr04', examId: 'eee1', studentId: 'sss4', grade: 85},{resultId: 'rrr05', examId: 'eee1', studentId: 'sss5', grade: 78},{resultId: 'rrr06', examId: 'eee1', studentId: 'sss6', grade: 84},{resultId: 'rrr07', examId: 'eee2', studentId: 'sss1', grade: 89},{resultId: 'rrr08', examId: 'eee2', studentId: 'sss2', grade: 88},{resultId: 'rrr09', examId: 'eee2', studentId: 'sss3', grade: 81},{resultId: 'rrr10', examId: 'eee2', studentId: 'sss4', grade: 95}]

// Math.Average.
Math.average = (...args) => (args.reduce((total, x) => total + x, 0) / args.length)

// Categorise.
const categorise = scores => scores.reduce((output, score) => {
  const {examId: id, grade} = score
  if (output[id]) output[id].push(grade)
  else output[id] = [grade]
  return output
}, {})

// Metrics.
const getMetrics = (exams, scores) => exams.map(exam => {
  const {examId: id, examName: name} = exam
  const s = scores[id] || []
  const isEmpty = !s.length
  return {
    name,
    count: s.length,
    min: isEmpty ? 0 : Math.min(...s),
    max: isEmpty ? 0 : Math.max(...s),
    average: isEmpty ? 0 : Math.average(...s)
  }
})

// Output + Proof.
const categorisedScores = categorise(scores)
const metrics = getMetrics(exams, categorisedScores)
console.log(metrics)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.