简体   繁体   English

通过比较对象的属性来过滤对象数组

[英]Filter array of objects by comparing their properties

I tried to find the highest score on an object in this array, but the result is incorrect.我试图在这个数组中找到一个对象的最高分,但结果不正确。 Should we reset the score to be 0 again?我们是否应该再次将分数重置为 0? I was trying to put the score variable below the obj[i.class] but nothing changed:我试图将 score 变量放在obj[i.class]下方,但没有任何改变:

 function theScore (students) { var obj = {}; score = 0; for(i of students){ if(score < i.score) { obj[i.class] = { name: i.name, score: i.score }; }; }; return obj; }; console.log(theScore([ { name: 'Sara', score: 90, class: 'A' }, { name: 'Poyi', score: 85, class: 'B' }, { name: 'Adert', score: 74, class: 'A' }, { name: 'Shynta', score: 78, class: 'B' } ]));

Desired output:期望的输出:

{
A: { 
        name: 'Sara',
        score: 90
   },
B: {
        name: 'Poyi',
        score: 85
   }
}

Can't you massively simplify your function's obj assignment?你不能大量简化函数的 obj 赋值吗?

function theScore (students) {
    var obj = {};
    var score = 0;
    for(i of students){
        if(i.score > score ) { 
            score = i.score;     // Keep track of the highest-score-found-so-far
            obj = i;             // Keep track of the highest scoring object
        }
    }
    return obj;
}

The score is not being changed after you find the highest score.找到最高分后,分数不会改变。 Change the score to the current score.将分数更改为当前分数。 Thanks.谢谢。 Instead of an object with map, use an object with index(Array).使用带有 index(Array) 的对象,而不是带有 map 的对象。 This should work.这应该有效。

function theScore (students) {
  var obj = [];
  score = 0;
  for(i of students){
    if(obj.length === 0) {
       obj.push( i );
    } else {
      for( var x = 0; x < obj.length; x++ ){
         if( i.score > obj[x].score ){
             obj.splice( x, 0, i );
             break;
         }
      }
      if( x === obj.length ){
        obj.push(i);
      }
    }
  };
  return obj;
};


console.log(theScore([
  {
    name: 'Sara',
    score: 90,
    class: 'A'
  },
  {
    name: 'Poyi',
    score: 85,
    class: 'B'
  },
  {
    name: 'Adert',
    score: 74,
    class: 'A'
  },
  {
    name: 'Shynta',
    score: 78,
    class: 'B'
  }
]));

The problem with your code is that you don't make any distinction between students' scores in one class versus another class.你的代码的问题是你没有区分一个班级和另一个班级的学生分数。 You also are not updating the score when you find a higher one, so every student's score (unless it's 0) will be higher than score every time your loop runs, and you just end up with the last score in the list.当您找到更高的分数时,您也不会更新分数,因此每次循环运行时,每个学生的分数(除非它是 0)都将高于score ,并且您最终会得到列表中的最后一个分数。

EDIT: edited to show how to do this with only one loop编辑:编辑以显示如何仅使用一个循环来执行此操作

You need to:你需要:

  1. Track score for each class每个班级的成绩
  2. Loop over the students在学生上循环
  3. Compare that student's score to the class high score for that student's class将该学生的分数与该学生班级的班级高分进行比较
  4. Update as needed根据需要更新
  5. Repeat until done.重复直到完成。

 function theScore (students) { const highScoresByClass = {}; const scores = {A: 0, B: 0, C: 0}; for (const student of students){ const classHighScore = scores[student.class]; if(classHighScore < student.score) { scores[student.class] = student.score; highScoresByClass[student.class] = { name: student.name, score: student.score }; }; }; return highScoresByClass; }; console.log(theScore([ { name: 'Sara', score: 90, class: 'A' }, { name: 'Poyi', score: 85, class: 'B' }, { name: 'Adert', score: 74, class: 'A' }, { name: 'Shynta', score: 78, class: 'B' } ]));

You need to track the already checked classes .您需要跟踪已检查的classes

A cleaner alternative is using the function Array.prototype.reduce to build the desired output.Array.prototype.reduce替代方法是使用函数Array.prototype.reduce来构建所需的输出。 As you can see, basically, this approach is keeping a track of the previously checked classes .如您所见,基本上,这种方法是跟踪先前检查过的classes

 function theScore (students) { return students.reduce((a, c) => { a[c.class] = (a[c.class] || (a[c.class] = c)); if (c.score > a[c.class].score) a[c.class] = c; return a; }, Object.create(null)); } console.log(theScore([ { name: 'Sara', score: 90, class: 'A' }, { name: 'Poyi', score: 85, class: 'B' }, { name: 'Adert', score: 74, class: 'A' }, { name: 'Shynta', score: 78, class: 'B' }]));
 .as-console-wrapper { max-height: 100% !important; top: 0; }

The issue with your code was never actually comparing the the actual object score but to 0 always.您的代码的问题实际上从未将实际对象分数进行比较,而是始终与 0 进行比较。

If you really want to use for in loop for this you can do something like (with slight changes to your code):如果您真的想为此使用for in循环,您可以执行以下操作(对代码稍作更改):

 var data = [ { name: 'Sara', score: 90, class: 'A' }, { name: 'Poyi', score: 85, class: 'B' }, { name: 'Adert', score: 74, class: 'A' }, { name: 'Shynta', score: 78, class: 'B' } ] function theScore (students) { var obj = {} for(i of students){ if(!obj[i.class] || obj[i.class].score < i.score) { obj[i.class] = {name: i.name, score: i.score} } } return obj } console.log(theScore(data))

Or you can use reduce and solve it like this:或者你可以使用reduce并像这样解决它:

 var data = [ { name: 'Sara', score: 90, class: 'A' }, { name: 'Poyi', score: 85, class: 'B' }, { name: 'Adert', score: 74, class: 'A' }, { name: 'Shynta', score: 78, class: 'B' } ] const maxByClass = (d) => d.reduce((r,{name, score, ...c}) => { r[c.class] = r[c.class] ? r[c.class].score > score ? r[c.class] : {name, score} : {name, score} return r }, {}) console.log(maxByClass(data))

Since reduce returns an accumulator we simply need to assign the correct object prop based on which one of the 2 classes scores is larger and return.由于reduce 返回一个累加器,我们只需要根据2 个类别中的哪一个分数较大并返回来分配正确的对象道具。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM