I have a vector with doubles which I want to rank (actually it's a vector with objects with a double member called costs
). If there are only unique values or I ignore the nonunique values then there is no problem. However, I want to use the average rank for nonunique values. Furthermore, I have found some question at SO about ranks, however they ignore the non-unique values.
Example, say we have (1, 5, 4, 5, 5) then the corresponding ranks should be (1, 4, 2, 4, 4). When we ignore the non-unique values the ranks are (1, 3, 2, 4, 5).
When ignoring the nonunique values I used the following:
void Population::create_ranks_costs(vector<Solution> &pop)
{
size_t const n = pop.size();
// Create an index vector
vector<size_t> index(n);
iota(begin(index), end(index), 0);
sort(begin(index), end(index),
[&pop] (size_t idx, size_t idy) {
return pop[idx].costs() < pop[idy].costs();
});
// Store the result in the corresponding solutions
for (size_t idx = 0; idx < n; ++idx)
pop[index[idx]].set_rank_costs(idx + 1);
}
Does anyone know how to take the non-unique values into account? I prefer using std::algorithm
since IMO this lead to clean code.
One way to do so would be using a
multimap
.Place the items in a multimap mapping your objects to
size_t
s (the intial values are unimportant). You can do this with one line (use the ctor that takes iterators).Loop (either plainly or using whatever from
algorithm
) and assign 0, 1, ... as the values.Loop over the distinct keys. For each distinct key, call
equal_range
for the key, and set its values to the average (again, you can use stuff fromalgorithm
for this).The overall complexity should be Theta(n log(n)), where n is the length of the vector.