简体   繁体   English

如何根据javascript中的最大值从对象数组中删除对象

[英]How can I remove an object from array of objects based on max value in javascript

I've got an array of objects that looks like this: 我有一个像这样的对象数组:

[ { person: 'Fred', scoreTotal: 29 },
{ person: 'Alice', scoreTotal: 34 },
{ person: 'Alice', scoreTotal: 22 },
{ person: 'Mary', scoreTotal: 14 },
{ person: 'Bob', scoreTotal: 33 },
{ person: 'Bob', scoreTotal: 13 },
{ person: 'Bob', scoreTotal: 22 },
{ person: 'Joe', scoreTotal: 28 }]

and where there are multiple objects for a given person -> I want to keep the top "X". 并且对于给定的人有多个对象 - >我想保持顶部的“X”。 For example: 例如:

a. 一个。 top 1 result for a person Result would look like this: 一个人的前1个结果结果如下所示:

    [ { person: 'Fred', scoreTotal: 29 },
    { person: 'Alice', scoreTotal: 34 },
    { person: 'Mary', scoreTotal: 14 },
    { person: 'Bob', scoreTotal: 33 },
    { person: 'Joe', scoreTotal: 28 }]

b. top 2 results for a person Result would look like this: 一个人的前2个结果结果如下所示:

   [ { person: 'Fred', scoreTotal: 29 },
  { person: 'Alice', scoreTotal: 34 },
   { person: 'Alice', scoreTotal: 22 },
   { person: 'Mary', scoreTotal: 14 },
   { person: 'Bob', scoreTotal: 33 },
   { person: 'Bob', scoreTotal: 22 },
   { person: 'Joe', scoreTotal: 28 }]

Is there a way to achieve this using something like Lodash? 有没有办法用Lodash这样的东西来实现这个目标?

I think I'm heading in the right direction with this but not quite there yet: 我想我正朝着正确的方向前进但尚未完全:

for (var i = 0; i < t.length - 1; i++) {
if (
  t[i].golfer === t[i + 1].golfer &&
  t[i].scoreTotal < t[i + 1].scoreTotal
) {
  delete t[i];
}

} }

// remove the "undefined entries" //删除“未定义的条目”

t = t.filter(function(el) {
    return typeof el !== "undefined";
});
console.log(t);

You can do this pretty simply without Underscore/Lodash. 没有Underscore / Lodash,你可以很简单地做到这一点。 Sort the array highest to lowest by score. 按分数将数组从最高到最低排序。 Then use Array.filter . 然后使用Array.filter As filter goes through the array keep track of how many times you see each person and start return false after the top number you want has been reached for a person. 当过滤器通过阵列时,记录您看到每个人的次数,并在达到您想要的最高号码后开始返回false。

 let arr = [ { person: 'Fred', scoreTotal: 29 },{ person: 'Alice', scoreTotal: 34 },{ person: 'Alice', scoreTotal: 22 },{ person: 'Mary', scoreTotal: 14 },{ person: 'Bob', scoreTotal: 33 },{ person: 'Bob', scoreTotal: 13 },{ person: 'Bob', scoreTotal: 22 },{ person: 'Joe', scoreTotal: 28 }] function filterTop(arr, top) { let counts = {} return [...arr].sort((a, b) => b.scoreTotal - a.scoreTotal) .filter(score => (counts[score.person] = (counts[score.person] || 0) +1 ) <= top) } console.log(filterTop(arr, 1)) console.log(filterTop(arr, 2)) 

Using only ES6, you can use 2 reduce s. 仅使用ES6,您可以使用2 reduce s。 First is to group the arrays. 首先是对数组进行分组。 the second is to get the number of top per group. 第二是获得每组最高人数。

 let arr = [{"person":"Fred","scoreTotal":29},{"person":"Alice","scoreTotal":34},{"person":"Alice","scoreTotal":22},{"person":"Mary","scoreTotal":14},{"person":"Bob","scoreTotal":33},{"person":"Bob","scoreTotal":13},{"person":"Bob","scoreTotal":22},{"person":"Joe","scoreTotal":28}]; let getTop = (a, t) => { //Parameters a = array. t = top return Object.values(a.reduce((c, v) => { //Group the array using the person property c[v.person] = c[v.person] || []; c[v.person].push(v); return c; }, {})).reduce((c, v) => { v.sort((a, b) => b.scoreTotal - a.scoreTotal); //Sort the sub array c = c.concat(v.slice(0, t)); //Add the top to accumulator return c; }, []); } let result1 = getTop(arr, 1); //Get top 1 let result2 = getTop(arr, 2); //Get top 2 console.log('Top 1', result1); console.log('Top 2', result2); 

Here is a solution with lodash... 这是lodash的解决方案......

function pickTopX(data, x) {
  let grouped = _.groupBy(data, 'person');
  let sorted = _.sortBy(grouped, 'scoreTotal');
  let sliced = _.map(sorted, function(pair) {
    return _.take(pair, x)
  });
  let result = _.flatten(sliced);
  return result;
}

This does exactly what you want in the exact order you want using the exact library you're trying to use (lodash). 使用您尝试使用的确切库(lodash),您可以按照您想要的确切顺序执行此操作。 I broke the process down into the following steps: 我把这个过程分解为以下步骤:

Step 1: group the data. 第1步:对数据进行分组。 There should be a an array containing all "Bob" records, and another array containing all "Joe" records, etc. I decided to go a step further and only store the scoreTotal rather than the entire record. 应该有一个包含所有“Bob”记录的数组,以及包含所有“Joe”记录的另一个数组等。我决定更进一步,只存储scoreTotal而不是整个记录。

Step 2: loop through each of these arrays, sort them in descending order, and slice to the desired "top" results. 第2步:循环遍历每个数组,按降序对它们进行排序,并切片到所需的“顶部”结果。

Step 3: filter the original data, using our previous findings and only include a record in the results if we have an exact scoreTotal match for a specific person, and only once per such score, removing it from our temporary array along the way so we don't get duplicate records and return more records than the "top" records desired. 第3步:使用我们之前的调查结果过滤原始数据,如果我们有一个特定人的确切评分总匹配,则只包含结果中的记录,并且每个评分只有一次,从我们的临时数组中删除它,所以我们不要获得重复记录并返回比所需“最高”记录更多的记录。

 // The magical function function showTopResults(input, topResults) { // Step one: group like data together var groupedData = _.reduce(input, function(result, value, key) { if(typeof result[value.person] == 'undefined'){ result[value.person] = []; } result[value.person].push(value.scoreTotal); return result; }, {}); // Step two: loop through person keys, sort it, then grab only the first "x" elements _.forEach(groupedData, function(value, key) { value = value.sort(function(a,b){ var n = b - a; return n ? n < 0 ? -1 : 1 : 0}); // first element is largest groupedData[key] = value.slice(0, topResults); // we only want first x results, so we get largest only }); // Step three: filter our elements only where we have a match var filterResults = _.filter(input,function(o){ var idx = _.indexOf(groupedData[o.person],o.scoreTotal); if( idx > -1) { groupedData[o.person].splice(idx, 1); // remove element so we don't get multiple elements of equal value return true; // We have a match } else { return false; // not a match } }); return filterResults; } // Our input var input = [ { person: 'Fred', scoreTotal: 29 }, { person: 'Alice', scoreTotal: 34 }, { person: 'Alice', scoreTotal: 22 }, { person: 'Mary', scoreTotal: 14 }, { person: 'Bob', scoreTotal: 33 }, { person: 'Bob', scoreTotal: 13 }, { person: 'Bob', scoreTotal: 22 }, { person: 'Joe', scoreTotal: 28 } ]; // Tests using our magical function console.log(showTopResults(input, 1)); console.log(showTopResults(input, 2)); 
 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script> 

Not exactly what you asked but worth considering: 不完全是你问的,但值得考虑:

The best way to handle this would be to restructure your data 处理此问题的最佳方法是重新构建数据

 var people = {}, personArray = [ { person: 'Fred', scoreTotal: 29 }, { person: 'Alice', scoreTotal: 34 }, { person: 'Alice', scoreTotal: 22 }, { person: 'Mary', scoreTotal: 14 }, { person: 'Bob', scoreTotal: 33 }, { person: 'Bob', scoreTotal: 13 }, { person: 'Bob', scoreTotal: 22 }, { person: 'Joe', scoreTotal: 28 } ]; //loop person Array to group array by person //and sort their top scores from best to worst for(var i = 0; i < personArray.length; i++){ var person = personArray[i].person, score = personArray[i].scoreTotal, scores = people[person] || [], pushed = false; if(scores.length){ for(var n = 0; n < scores.length; n++){ if(score > scores[n]){ pushed = true; scores.splice(n, 0, score); break; } } } if(!pushed) scores.push(score); people[person] = scores; } console.log(people); //return top `n` scores for each person from best to worst function topScores(nScores){ var result = []; for(var name in people){ if(people.hasOwnProperty(name)){ for(var r = 0; ((r < people[name].length) && (r < nScores)); r++){ result.push({person: name, scoreTotal: people[name][r]}); } } } return result } console.log(topScores(2)) console.log(topScores(3)) console.log(topScores(1)) 

Reduce the array to an object, using the person prop as key. 使用person prop作为键将数组减少为对象。 For each person add to object, if key doesn't exists or if scoreTotal is greater than current scoreTotal . 对于每个人添加到对象,如果键不存在或者scoreTotal大于当前scoreTotal Convert back to array using Object.values() : 使用Object.values()转换回数组:

 const data = [{"person":"Fred","scoreTotal":29},{"person":"Alice","scoreTotal":34},{"person":"Alice","scoreTotal":22},{"person":"Mary","scoreTotal":14},{"person":"Bob","scoreTotal":33},{"person":"Bob","scoreTotal":13},{"person":"Bob","scoreTotal":22},{"person":"Joe","scoreTotal":28}]; const result = Object.values(data.reduce((r, p) => { if(!r[p.person] || r[p.person].scoreTotal < p.scoreTotal) { r[p.person] = p; } return r; }, {})); console.log(result); 

This isn't a full answer, just a tip. 这不是一个完整的答案,只是一个提示。 Don't use delete array[index] , use array.splice . 不要使用delete array[index] ,请使用array.splice See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice for more info. 有关详细信息,请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

The next suggestion is to clarify whether you actually need to modify the array, or just get a new array without some of the original array's data. 下一个建议是澄清你是否真的需要修改数组,或者只是在没有原始数组数据的情况下获得一个新数组。 If you do not need to modify the original, it is far better to just use a function like reduce, or use a for loop to selectively copy items into the new array. 如果您不需要修改原始文件,最好只使用reduce之类的函数,或使用for循环有选择地将项目复制到新数组中。

Using underscore: https://underscorejs.org/ 使用下划线: https//underscorejs.org/

 const db = [ { person: 'Fred', scoreTotal: 29 }, { person: 'Fred', scoreTotal: 10 }, { person: 'Fred', scoreTotal: 2 }, { person: 'Alice', scoreTotal: 34 }, { person: 'Alice', scoreTotal: 5 }, { person: 'Alice', scoreTotal: 15 }, { person: 'Alice', scoreTotal: 40 }, { person: 'Mary', scoreTotal: 23 }, { person: 'Mary', scoreTotal: 32 }, { person: 'Mary', scoreTotal: 98 }, { person: 'Mary', scoreTotal: 4 }, { person: 'Bob', scoreTotal: 70 }, { person: 'Bob', scoreTotal: 65 }, { person: 'Bob', scoreTotal: 35 }, { person: 'Bob', scoreTotal: 5 }, { person: 'Joe', scoreTotal: 28 }]; const nOfItens = 2; const persons = _.map(db, item => item.person); const names = _.uniq(persons); let newList = []; for (var i = 0; names.length > i; i++) { let filter = _.filter(db, person => person.person === names[i]); let sort = _.sortBy(filter, num => -num.scoreTotal); let items = sort.splice(0, nOfItens) newList = [...newList, ...items] } console.log(newList); 
 <script src="https://underscorejs.org/underscore-min.js"></script> 

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

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