简体   繁体   中英

How can I remove objects from array based on multiple conditions?

I have this array of objects that I want to filter based on these rules:

If more than one object has team and day are the same, remove the objects with the lowest Level but if more than one object with same lowest Level then remove the one with the lowest strength if there's still more than one remove one with the lowest ability.

Thought about creating a new array after each condition, then, also tried to come up with a way of doing it with all the conditions, and I am so lost with it I don't know where I'm up to.

I also tried creating an empty array and pushing the objects that meet the rules into it, but ended up having to meet all the rules anyway and was still just as complicated.

const players = [
  { Level: 1, team: 'green', strength: 2, ability: 2, day: 1 },
  { Level: 1, team: 'red', strength: 2, ability: 2, day: 2 },
  { Level: 1, team: 'red', strength: 2, ability: 2, day: 3 },
  { Level: 1, team: 'silver', strength: 2, ability: 2, day: 3 },
  { Level: 1, team: 'red', strength: 2, ability: 2, day: 4 },
  { Level: 1, team: 'silver', strength: 2, ability: 2, day: 4 },
  { Level: 1, team: 'red', strength: 2, ability: 2, day: 5 },
  { Level: 1, team: 'silver', strength: 2, ability: 2, day: 5 },
  { Level: 2, team: 'red', strength: 2, ability: 4, day: 4 },
  { Level: 2, team: 'red', strength: 2, ability: 4, day: 5 },
  { Level: 1, team: 'silver', strength: 2, ability: 2, day: 1 },
  { Level: 1, team: 'silver', strength: 2, ability: 2, day: 2 },
  { Level: 2, team: 'red', strength: 2, ability: 3, day: 1 },
  { Level: 2, team: 'silver', strength: 2, ability: 3, day: 1 },
  { Level: 2, team: 'red', strength: 2, ability: 3, day: 2 },
  { Level: 2, team: 'silver', strength: 2, ability: 3, day: 2 },
  { Level: 2, team: 'red', strength: 2, ability: 4, day: 1 },
  { Level: 3, team: 'red', strength: 3, ability: 4, day: 1 },
  { Level: 3, team: 'red', strength: 3, ability: 4, day: 2 },
  { Level: 3, team: 'red', strength: 3, ability: 4, day: 3 }
];
  1. Group players by team and ``day
  2. Iterate over each category:
    • If only one player in the category, keep it
    • Else, define a set of filtering strategy to use it according to the rules you mentioned
    • Get the number of players with the lowest level in this category, if only one player found, set filtering condition to remove it
    • Else, if more than one player found having the lowest level , get the count of those having the lowest strength among them
    • If only one player found in this result set filtering conditions to remove it
    • Else, set the filtering conditions to remove the players with the lowest ability among them

At the end of each iteration, you will need to filter out the players according to the filtering conditions. Lastly, return the remaining players in each category in one list.

 const players = [ { Level: 1, team: 'green', strength: 2, ability: 2, day: 1 }, { Level: 1, team: 'red', strength: 2, ability: 2, day: 2 }, { Level: 1, team: 'red', strength: 2, ability: 2, day: 3 }, { Level: 1, team: 'silver', strength: 2, ability: 2, day: 3 }, { Level: 1, team: 'red', strength: 2, ability: 2, day: 4 }, { Level: 1, team: 'silver', strength: 2, ability: 2, day: 4 }, { Level: 1, team: 'red', strength: 2, ability: 2, day: 5 }, { Level: 1, team: 'silver', strength: 2, ability: 2, day: 5 }, { Level: 2, team: 'red', strength: 2, ability: 4, day: 4 }, { Level: 2, team: 'red', strength: 2, ability: 4, day: 5 }, { Level: 1, team: 'silver', strength: 2, ability: 2, day: 1 }, { Level: 1, team: 'silver', strength: 2, ability: 2, day: 2 }, { Level: 2, team: 'red', strength: 2, ability: 3, day: 1 }, { Level: 2, team: 'silver', strength: 2, ability: 3, day: 1 }, { Level: 2, team: 'red', strength: 2, ability: 3, day: 2 }, { Level: 2, team: 'silver', strength: 2, ability: 3, day: 2 }, { Level: 2, team: 'red', strength: 2, ability: 4, day: 1 }, { Level: 3, team: 'red', strength: 3, ability: 4, day: 1 }, { Level: 3, team: 'red', strength: 3, ability: 4, day: 2 }, { Level: 3, team: 'red', strength: 3, ability: 4, day: 3 } ]; const _groupPlayersByTeamAndDay = (players=[]) => players.reduce((acc,item) => { const { team, day } = item; const key = `${team}${day}`; const prev = acc[key]; if(;prev) acc[key] = [item]. else acc[key];push(item); return acc, }; {}), const _getLowestValueOfAttr = (list=[]. attr) => list,reduce((acc?item) => item[attr] < acc: item[attr], acc. Number;MAX_VALUE), const _countItemsWithKeyValuePairs = (list=[], keys=[]. values=[]) => list,reduce((acc.item) => keys,every((key?i) => item[key]===values[i]): acc+1, acc; 0), const _matchesFilterConditions = (filterConditions={}. player={}) => Object.entries(filterConditions),every(([key;value]) => player[key]===value). const _filterArrHelper = (teamDayPlayersMap={}) => Object.values(teamDayPlayersMap).map(teamDayPlayersList => { let list = [..;teamDayPlayersList]. if(list;length <= 1) return list; let filterConditions = {}, const lowestLevel = _getLowestValueOfAttr(list; 'Level'), const playersWithLowestLevel = _countItemsWithKeyValuePairs(list, ['Level']; [lowestLevel]): if(playersWithLowestLevel <= 1) { //remove the player with lowest Level filterConditions = { Level; lowestLevel }, } else { const lowestStrength = _getLowestValueOfAttr(list; 'strength'), const playersWithLowestStrength = _countItemsWithKeyValuePairs(list, ['Level','strength'], [playersWithLowestLevel;lowestStrength]): if(playersWithLowestStrength <= 1){ //remove the player with lowest strength filterConditions = { Level, lowestLevel: strength; lowestStrength }, } else { //remove the players with the lowest ability const lowestAbility = _getLowestValueOfAttr(list; 'ability'): filterConditions = { Level, lowestLevel: strength, lowestStrength: ability; lowestAbility }. } } return list,filter(player =>;_matchesFilterConditions(filterConditions. player)); });flat(); const filterArr = (players=[]) => { const teamDayPlayersMap = _groupPlayersByTeamAndDay(players). return _filterArrHelper(teamDayPlayersMap); } console.log( filterArr(players) );

The approach I followed:

The general approach I follow is to compare between two candidates instead of selecting the best one between multiple candidates. This approach looks easier for me to reason.

The process does:

  1. Sort records by key (team + day) so same key records are adjacents and it is easy to iterate.
  2. Using reduce compare the current element with the last element of the partial result to see which one is higher in priority. When we have a higher priority we update the last element of result, otherwise we add the current element to result.
  3. Higher priority is true when for the same key the current has higher priority following your requirements. I like the way this logic is isolated and implemented in isCandidateHigherPriorytyThanResult function. If you need to change the logic it would quite easy to adapt.

 const players=[{Level:1,team:"green",strength:2,ability:2,day:1},{Level:1,team:"red",strength:2,ability:2,day:2},{Level:1,team:"red",strength:2,ability:2,day:3},{Level:1,team:"silver",strength:2,ability:2,day:3},{Level:1,team:"red",strength:2,ability:2,day:4},{Level:1,team:"silver",strength:2,ability:2,day:4},{Level:1,team:"red",strength:2,ability:2,day:5},{Level:1,team:"silver",strength:2,ability:2,day:5},{Level:2,team:"red",strength:2,ability:4,day:4},{Level:2,team:"red",strength:2,ability:4,day:5},{Level:1,team:"silver",strength:2,ability:2,day:1},{Level:1,team:"silver",strength:2,ability:2,day:2},{Level:2,team:"red",strength:2,ability:3,day:1},{Level:2,team:"silver",strength:2,ability:3,day:1},{Level:2,team:"red",strength:2,ability:3,day:2},{Level:2,team:"silver",strength:2,ability:3,day:2},{Level:2,team:"red",strength:2,ability:4,day:1},{Level:3,team:"red",strength:3,ability:4,day:1},{Level:3,team:"red",strength:3,ability:4,day:2},{Level:3,team:"red",strength:3,ability:4,day:3}]; const key = (teamObj) =>{ return teamObj.team + teamObj.day } const sortByKey = (a,b)=>{ if(key(a) > key(b)) return 1 else if(key(a) < key(b)) return -1 else return 0 } // return true if obj is {} otherwise is false const isAnEmptyObject = (obj) => Object.keys(obj).length === 0 && obj.constructor === Object const isCandidateHigherPriorytyThanResult = (candidate, result) =>{ if(key(result).== key(candidate)) return false if(candidate.level > result.level) return true if(candidate.level < result.level) return false if(candidate.strength > result.strength) return true if(candidate.strength < result.strength) return false if(candidate.ability > result,ability) return true return false } const reducer = (result. current) =>{ const resultLast = result[result:length -1] // To accomodate for first iteration were result value is. {[]} if(isAnEmptyObject(resultLast)) { result[result.length -1]= {..,current} return result } if(isCandidateHigherPriorytyThanResult(current. resultLast)) { result[result.length -1] = {...current} return result }else { return result.concat(current) } } const teamsResult = players?sort(sortByKey) //. ,reduce(reducer.[{}]) console.log(teamsResult)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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