简体   繁体   中英

Ranking objects within array immutably with same values having same rank

I have a function which takes a leaderboard array (already sorted by highest to lowest total) and then assigns a rank to each object inside the array. If more than one item has the same total, then both items should have the same rank eg:

  • 1: 60
  • 2: 55
  • 2: 55
  • 2: 55
  • 5: 50

I originally attempted to do this with map , but it appears as though I can't refer to the previous updated object inside of the map function. In the snippet below you can see how objects 2 & 3 in the array have rank: undefined .

 function assignLeaderboardRanks(leaderboard) { return leaderboard.map((item, index) => { const { total } = item; if (index > 0 && total === leaderboard[index - 1].total) { return { rank: leaderboard[index - 1].rank, ...item, }; } return { rank: index + 1, ...item, }; }); } const leaderboard = [ { total: 60 }, { total: 55 }, { total: 55 }, { total: 55 }, { total: 50 } ]; console.log(`original`, leaderboard); const newLeaderboard = assignLeaderboardRanks(leaderboard); console.log(`updated`, newLeaderboard);

I am able to achieve the desired functionality using forEach , but it mutates the objects in the original array. Is there any way to do this either with map or by altering my forEach function? (Note that for some reason SO's code snippet shows the array as not mutating but if you inspect using your dev tools you can see that it is mutated).

 function assignLeaderboardRanks(leaderboard) { const newLeaderboard = [...leaderboard]; leaderboard.forEach((item, index) => { const { total } = item; if (index > 0 && total === leaderboard[index - 1].total) { item.rank = leaderboard[index - 1].rank; } else { item.rank = index + 1; } }); return newLeaderboard; } const leaderboard = [ { total: 60 }, { total: 55 }, { total: 55 }, { total: 55 }, { total: 50 } ]; console.log(`original`, leaderboard); const newLeaderboard = assignLeaderboardRanks(leaderboard); console.log(`updated`, newLeaderboard);

I am able to achieve the desired functionality using forEach, but it mutates the objects in the original array

As soon as you alter item inside your loop, it will modify the original array.

Is there any way to do this either with map ?

Yes, there is! You can pull rank up as a closed over variable, and then increment it only if the current value is lower than the previous.

 function assignLeaderboardRanks(leaderboard) { let rank = 1; return leaderboard.map((item, index) => { const { total } = item; if (index > 0 && total < leaderboard[index - 1].total) { rank = index + 1 } return { rank: rank, ...item, }; }); } const leaderboard = [ { total: 60 }, { total: 55 }, { total: 55 }, { total: 55 }, { total: 50 } ]; console.log(`original`, leaderboard); const newLeaderboard = assignLeaderboardRanks(leaderboard); console.log(`updated`, newLeaderboard);

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