Alex338207
Alex338207

Reputation: 1905

indices of unique elements of vector in Julia

How to get indexes of unique elements of a vector?

For instance if you have a vector v = [1,2,1,3,5,3], the unique elements are [1,2,3,5] (output of unique) and their indexes are ind = [1,2,4,5]. What function allows me to compute ind so that v[ind] = unique(v) ?

Upvotes: 7

Views: 7966

Answers (4)

ederag
ederag

Reputation: 2509

A mix between mattswon and Bogumił Kamiński answers (thanks !):

uniqueidx(v) = unique(i -> v[i], eachindex(v))

eachindex allows to work with any kind of array, even views.

julia> v = [1,2,1,3,5,3];

julia> uniqueidx(v)
4-element Vector{Int64}:
 1
 2
 4
 5

julia> v2 = reshape(v, 2, 3)
2×3 Matrix{Int64}:
 1  1  5
 2  3  3

julia> subv2 = view(v2, 1:2, 1:2)
2×2 view(::Matrix{Int64}, 1:2, 1:2) with eltype Int64:
 1  1
 2  3

julia> uniqueidx(subv2)
3-element Vector{CartesianIndex{2}}:
 CartesianIndex(1, 1)
 CartesianIndex(2, 1)
 CartesianIndex(2, 2)

Upvotes: 6

mattswoon
mattswoon

Reputation: 111

Another suggestion is

unique(i -> x[i], 1:length(x))

which is about as fast as the function in the accepted answer (in Julia 1.1), but a bit briefer.

Upvotes: 11

niczky12
niczky12

Reputation: 5073

If you don't care about finding the first index for each unique element, then you can use a combination of the unique and indexin functions:

julia> indexin(unique(v), v)
4-element Array{Int64,1}:
 3
 2
 6
 5

Which gets one index for each unique element of v in v. These are all in base and works in 0.6. This is about 2.5 times slower than @Bogumil's function, but it's a simple alternative.

Upvotes: 5

Bogumił Kamiński
Bogumił Kamiński

Reputation: 69939

This is a solution for Julia 0.7:

findfirst.(isequal.(unique(x)), [x])

or similar working under Julia 0.6.3 and Julia 0.7:

findfirst.(map(a -> (y -> isequal(a, y)), unique(x)), [x])

and a shorter version (but it will not work under Julia 0.7):

findfirst.([x], unique(x))

It will probably not be the fastest.

If you need speed you can write something like (should work both under Julia 0.7 and 0.6.3):

function uniqueidx(x::AbstractArray{T}) where T
    uniqueset = Set{T}()
    ex = eachindex(x)
    idxs = Vector{eltype(ex)}()
    for i in ex
        xi = x[i]
        if !(xi in uniqueset)
            push!(idxs, i)
            push!(uniqueset, xi)
        end
    end
    idxs
end

Upvotes: 9

Related Questions