I required something similar to this some time ago and came up with this:
function sortedRank(arr, childProp, asc) {
let prev, position = 0, ranking = 0;
return [...arr]
.sort((a, b) => asc ? a[childProp] - b[childProp] : b[childProp] - a[childProp])
.map((target, idx) => {
const obj = { target };
obj.indexRank = idx + 1;
if (target[childProp] != prev) {
position = obj.rank = obj.indexRank;
ranking++;
prev = target[childProp];
} else {
obj.rank = position;
}
obj.altRank = ranking;
return obj
});
}
It returns 3 different ranking types together with the child object from the original array.
Where resultArr[0].rank is the rank from 1-N, but skips equal rank numbers.
For example:
source = resultArr[index].rank
goals 5 = 1.
goals 4 = 2.
goals 4 = 2.
goals 3 = 4.
goals 1 = 5.
resultArr[0].altRank doesn't skip ranking numbers.
source = resultArr[index].altRank
goals 5 = 1.
goals 4 = 2.
goals 4 = 2.
goals 3 = 3.
goals 1 = 4.
and indexRank is the position after sorting.
const list = [
{"name": "player1","goals": "5"},
{"name": "player5","goals": "4"},
{"name": "player2","goals": "4"},
{"name": "player3","goals": "2"},
{"name": "player4","goals": "1"}
];
function sortedRank(arr, childProp, ascending) {
let prev, position = 0,
ranking = 0;
return [...arr]
.sort((a, b) => ascending ? a[childProp] - b[childProp] : b[childProp] - a[childProp])
.map((target, idx) => {
const obj = { target };
obj.indexRank = idx + 1;
if (target[childProp] != prev) {
position = obj.rank = obj.indexRank;
ranking++;
prev = target[childProp];
} else {
obj.rank = position;
}
obj.altRank = ranking;
return obj
});
}
sortedRank(list, 'goals').forEach(({ indexRank, rank, altRank, target }) => {
console.log(`idxRank: ${indexRank} rank: ${rank} alternative: ${altRank}`, target);
});