Ranking array elements
This won't work with older browsers because it uses ECMAScript 5 features, but it allows you to quickly and succinctly produce an array of rankings even for very large arrays. (It doesn't use indexOf
which does a linear search and thus can be slow for large arrays.)
function cmp_rnum(a,b) {
// comparison function: reverse numeric order
return b-a;
}
function index_map(acc, item, index) {
// reduction function to produce a map of array items to their index
acc[item] = index;
return acc;
}
function ranks(v) {
var rankindex = v.slice().sort(cmp_rnum).reduceLeft(index_map, Object.create(null));
// reduceLeft() is used so the lowest rank wins if there are duplicates
// use reduce() if you want the highest rank
return v.map(function(item){ return rankindex[item]+1; });
}
Example output:
> ranks([79, 5, 18, 5, 32, 1, 16, 1, 82, 13]);
[2, 7, 4, 7, 3, 9, 5, 9, 1, 6]
var arr = [79, 5, 18, 5, 32, 1, 16, 1, 82, 13];
var sorted = arr.slice().sort(function(a,b){return b-a})
var ranks = arr.map(function(v){ return sorted.indexOf(v)+1 });
console.log(ranks);
Result :
[2, 7, 4, 7, 3, 9, 5, 9, 1, 6]
If you want to be compatible with old browsers, you may have to define a shim for indexOf and for map (note that if you want to do this very fast for very big arrays, you'd better use for
loops and use an object as map instead of indexOf
).