Derived Computed Data from Javascript Array

时间:2018-03-22 23:46:47

标签: javascript reactjs ecmascript-6 redux reselect

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

I have this array

students: [
  {studentId: 'sss1', isAthlete: true, isHonors: true, testScore: 78, studentName: 'Bobby'},
  {studentId: 'sss2', isAthlete: false, isHonors: false, testScore: 93, studentName: 'Sally'},
  {studentId: 'sss3', isAthlete: true, isHonors: true, testScore: 82, studentName: 'Mikey'}, 
  {studentId: 'sss4', isAthlete: false, isHonors: false, testScore: 88, studentName: 'Billy'}, 
  {studentId: 'sss5', isAthlete: true, isHonors: false, testScore: 91, studentName: 'Davey'}, 
  {studentId: 'sss6', isAthlete: false, isHonors: false, testScore: 94, studentName: 'Joey'}, 
  {studentId: 'sss7', isAthlete: false, isHonors: true, testScore: 97, studentName: 'Nancy'}, 
  {studentId: 'sss8', isAthlete: true, isHonors: false, testScore: 83, studentName: 'Susie'}, 
  {studentId: 'sss9', isAthlete: false, isHonors: false, testScore: 72, studentName: 'Jimmy'}, 

]

The above array is computed using reselect and then injected into my React component perfectly.

Now, in my react component I need to show my user this:

Total Student Count: 9
Total Athlete Count: 4
Total Honors Count: 3

Average Overall Score: 86.44
Average Honors Score: 85.67
Average Athlete Score: 83.5

Highest Overall Student: Nancy
Highest Honors Student: Nancy
Highest Athlete Student: Davey

My Questions
1. What is the "best practice" for where to make this calculation?
2. Can anyone dream up an array method to efficiently make this calculation? My actual array has hundreds of students.

Not trying to be a free-loader here but found myself writing dozens of these:

const athCount = students.filter(s => s.isAthlete === true).length

And have that tingling feeling that I'm doing it wrong.

THANK YOU

3 个答案:

答案 0 :(得分:1)

  1. Can anyone dream up an array method to efficiently make this calculation? My actual array has hundreds of students.

You need to iterate the array. There is no other way. However you might only do that once:

  let athletes = 0, honors = 0, honorScore = 0, athleteScore= 0, totalScore = 0, best = { score: 0 };
  for(const student of students){ 
   athletes += student.isAthlete;
   honors += student.isHonors;
   totalScore += student.score;
   /*...*/
   if(student.score > best.score)
      best = student;
 }

答案 1 :(得分:1)

    const data = [
  {studentId: 'sss1', isAthlete: true, isHonors: true, testScore: 78, studentName: 'Bobby'},
  {studentId: 'sss2', isAthlete: false, isHonors: false, testScore: 93, studentName: 'Sally'},
  {studentId: 'sss3', isAthlete: true, isHonors: true, testScore: 82, studentName: 'Mikey'}, 
  {studentId: 'sss4', isAthlete: false, isHonors: false, testScore: 88, studentName: 'Billy'}, 
  {studentId: 'sss5', isAthlete: true, isHonors: false, testScore: 91, studentName: 'Davey'}, 
  {studentId: 'sss6', isAthlete: false, isHonors: false, testScore: 94, studentName: 'Joey'}, 
  {studentId: 'sss7', isAthlete: false, isHonors: true, testScore: 97, studentName: 'Nancy'}, 
  {studentId: 'sss8', isAthlete: true, isHonors: false, testScore: 83, studentName: 'Susie'}, 
  {studentId: 'sss9', isAthlete: false, isHonors: false, testScore: 72, studentName: 'Jimmy'}, 
]

const initialResult = {
  count : {
    athlete : 0,
    honors : 0,
    total : 0
  },
  accumulate : {
    athlete : 0,
    honors : 0,
    total : 0
  },
  best : {
    name : null,
    score : null
  }
};

const result = data.reduce(process, initialResult);


function process (result, record) {
  result.count.total++;
  result.accumulate.total += record.testScore;

  if (record.isAthlete) {
    result.count.athlete++;
    result.accumulate.athlete += record.testScore;
  }
  if (record.isHonors) {
    result.count.honors++;
    result.accumulate.honors += record.testScore;
  }



  let best = result.best;

  if (best.name === null && best.score === null) {
    best.name = record.studentName;
    best.score = record.testScore;
  } else {
    if (best.score < record.testScore) {
      best.name = record.studentName;
      best.score = record.testScore;
    }
  } 

  return result;
}

console.log(result);

答案 2 :(得分:1)

答案1:在不知道输入数据变化的频率的情况下,我认为您应该将所有计算放在render函数中。这样,DOM始终与数据保持一致。在大多数情况下,这将很好地工作,你不会注意到任何性能影响。

答案2:在此示例中,_lodash package

const athletes = students.filter(({isAthlete}) => isAthlete);
const athleteCount = athletes.length;

const averageScore = _.sumBy(students, 'testScore') / students.length;
const averageHonorsScore = _.sumBy(athletes, 'testScore') / students.length;

const highestSCore = _.maxBy(students, 'testScore')
const highestAthleteScore = _.maxBy(athletes, 'testScore');