# Ranking of elements of a vector

**URL:** <https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293>\
**Category:** General Usage\
**Tags:** vector, ranking\
**Created:** [October 5, 2022, 1:39pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293 "2022-10-05T13:39:31Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![structural](https://avatars.discourse-cdn.com/v4/letter/s/34f0e0/32.png) [@structural](https://discourse.julialang.org/u/structural)\
**Post date:** [October 5, 2022, 1:39pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/1 "2022-10-05T13:39:31Z")

</div>

I have a vector `A`. I need a vector `RA` which ranks each element of `A`. Is there a better way to do this than what I have below?

```julia
A = [4;2;5;1;6;7]
RA = sum((A .== sort(A)') .* cumsum(ones(length(A)))', dims=2)

display([A RA])

```

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 5, 2022, 1:55pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/2 "2022-10-05T13:55:16Z")

</div>

```julia
julia> sortperm(A)
6-element Vector{Int64}:
 4
 2
 1
 3
 5
 6

julia> A[sortperm(A)]
6-element Vector{Int64}:
 1
 2
 4
 5
 6
 7

```

do you want some kind of sortperm?

---

<div class="post-metadata">

**Author:** ![Tbl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbl/32/5984_2.png) [@Tbl](https://discourse.julialang.org/u/Tbl)\
**Post date:** [October 5, 2022, 3:04pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/3 "2022-10-05T15:04:04Z")

</div>

I think they mean the inverse of `sortperm`, the solution would be `invperm(sortperm(A))`.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 5, 2022, 3:05pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/4 "2022-10-05T15:05:12Z")

</div>

ehh, `sortperm(; rev = true)`?

---

<div class="post-metadata">

**Author:** ![Tbl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbl/32/5984_2.png) [@Tbl](https://discourse.julialang.org/u/Tbl)\
**Post date:** [October 5, 2022, 3:13pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/5 "2022-10-05T15:13:17Z")

</div>

If I understand the problem correctly, the result should be vector with indices of the elements after sorting, for `A` it would be `[3 2 4 1 5 6]`. Command `sortperm(A, rev = true)` does not return it, `invperm(sortperm(A))` does.

---

<div class="post-metadata">

**Author:** ![structural](https://avatars.discourse-cdn.com/v4/letter/s/34f0e0/32.png) [@structural](https://discourse.julialang.org/u/structural)\
**Post date:** [October 5, 2022, 3:20pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/6 "2022-10-05T15:20:04Z")

</div>

Thanks `invperm(sortperm(A))` solves it

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [October 5, 2022, 3:57pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/7 "2022-10-05T15:57:33Z")

</div>

just as an alternative to the first proposal 😀

```julia
[findfirst(sa->sa==a, sort(A)) for a in A]

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [October 5, 2022, 5:44pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/8 "2022-10-05T17:44:33Z")

</div>

This function built on a simple loop, could be an extra argument in favor of the thesis (which is not mine: I prefer the `invperm (...)`) solution) that sometimes a for loop may be preferable to the use of Base library functions

```julia

function rankfy1(A)
rank=Int[]
for a in A
    r=1
    for i in eachindex(A)
        if a > A[i]
            r+=1
        end
    end
    push!(rank, r)
end
return rank
end

```

#or better

```julia

function rankfy2(A)
rank=similar(A)
for i in eachindex(A)
    r=1
    for ii in eachindex(A)
        if A[i] > A[ii]
            r+=1
        end
    end
    rank[i]=r
end
return rank
end

```

---

<div class="post-metadata">

**Author:** ![Tbl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbl/32/5984_2.png) [@Tbl](https://discourse.julialang.org/u/Tbl)\
**Post date:** [October 5, 2022, 8:02pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/9 "2022-10-05T20:02:16Z")

</div>

If we are playing with the code this algorithm can be also expressed as `[count(<=(a),A) for a in A]`; if we do not want `Base` one can also write the same thing like this

```julia
map(A) do a 
    S = 0
    for b in A
        b <= a && (S += 1)
    end
    S
end

```

All are O(n^2), so not very good.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [October 5, 2022, 8:51pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/10 "2022-10-05T20:51:32Z")

</div>

OK.  
I had done some quick tests on the vector A proposed by the OP.  
On larger vectors invperm () proves to be much more efficient.  
This confirms me in the idea that, whenever possible, it is better to use functions written by “expert” developers rather than relying on your own loops.

This, for example, does not perform as `invperm (sortperm ())` but is much better than just looping.

```julia
A=rand(1:10^8, 10^5)
last.(sort(tuple.(sort(tuple.(A,1:length(A)), by=first), 1:length(A)), by=last∘first))

```

PS  
what is the non-O (n ^ 2) algorithm used by invperm (…)?

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [October 6, 2022, 10:17am UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/11 "2022-10-06T10:17:21Z")

</div>

See [Rankings and Rank Correlations · StatsBase.jl](https://juliastats.org/StatsBase.jl/stable/ranking/) for general ranking: it lets you disambiguate ranks when ties are present.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [October 6, 2022, 1:40pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/12 "2022-10-06T13:40:55Z")

</div>

It seems to do something like this, obviously in a much more general way.

```julia
function rank1(A) 
    sp=sortperm(A)
    invsp=Array{Int}(undef, length(A))
    foreach(i->invsp[sp[i]]=i, eachindex(A))
    return invsp
end

```

---

<div class="post-metadata">

**Author:** ![Tbl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbl/32/5984_2.png) [@Tbl](https://discourse.julialang.org/u/Tbl)\
**Post date:** [October 7, 2022, 2:58pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/13 "2022-10-07T14:58:16Z")

</div>

In Julia you can check where the body of the function is with `@which` and even display it directly by `@edit`. If you use them you will get `invperm` algorithm. This algorithm is essentially simple

```julia
function myInvperm(p)
    res = Vector{Int}(undef,size(p))
    res[p] .= 1:length(p)
end

```

This is O(n)

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [October 7, 2022, 3:17pm UTC](https://discourse.julialang.org/t/ranking-of-elements-of-a-vector/88293/14 "2022-10-07T15:17:59Z")

</div>

Thank you.  
Especially for the last line

`res [p] = 1: length (p)`

This allows me to rewrite the function in the following way.

PS  
I noticed that explicitly using the `return invsp, @btime` calculates one less allocation.

```julia
julia> function rank2(A) 
           sp=sortperm(A)
           invsp=Array{Int}(undef, length(A))
           invsp[sp]=eachindex(A)
       end
rank2 (generic function with 1 method)

julia> @btime rank2(A);
  5.804 ms (6 allocations: 1.53 MiB)

julia> function rank2(A) 
           sp=sortperm(A)
           invsp=Array{Int}(undef, length(A))
           invsp[sp]=eachindex(A)
           return invsp
       end
rank2 (generic function with 1 method)

julia> @btime rank2(A);
  5.834 ms (5 allocations: 1.53 MiB)

```
