# Get indices of unique rows in 2D array

**URL:** <https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208>\
**Category:** General Usage\
**Tags:** indexing, matrix\
**Created:** [January 24, 2024, 7:52pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208 "2024-01-24T19:52:23Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![dalarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dalarev/32/9881_2.png) [@dalarev](https://discourse.julialang.org/u/dalarev)\
**Post date:** [January 24, 2024, 7:52pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/1 "2024-01-24T19:52:23Z")

</div>

MWE:

> `A = [1 2 ; 3 4 ; 1 2]`

I want as output the row indices `1, 2`.

Using `unique`, one can access the indices of unique values by using `i = unique(i -> A[i], eachindex(A))`, however I don’t know how to modify this for 2D arrays.

Appreciate any guidance. Context is I have a list of (x,y,z) coordinates (Mx3 array) where there are duplicate (x,y) values, and I’m trying to get rid of them. There may be a better way to do this. This issue is preventing me from gridding mesh coordinates using `GMT`, `LinearInterpolations`, and other packages.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 24, 2024, 8:01pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/2 "2024-01-24T20:01:04Z")

</div>

To get rid of the repeated rows:  
`unique(A, dims=1)`

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 24, 2024, 8:11pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/3 "2024-01-24T20:11:45Z")

</div>

To get the indices of the first unique rows, perhaps:

```julia
ix = unique(i -> A[i, :], axes(A, 1))

```

---

<div class="post-metadata">

**Author:** ![dalarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dalarev/32/9881_2.png) [@dalarev](https://discourse.julialang.org/u/dalarev)\
**Post date:** [January 24, 2024, 8:15pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/4 "2024-01-24T20:15:26Z")

</div>

This works! `axes(A, 1)` was the missing piece.

Thank you!

---

<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:** [January 25, 2024, 3:37pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/5 "2024-01-25T15:37:42Z")

</div>

a handmade one, but much more efficient

```julia
function distindrow(m)
    d=Dict{SubArray{Int64, 1, Matrix{Int64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true},Int}()
    #d=Dict{Array{Int},Int}()
    for (i,e) in enumerate(eachrow(m))
        d[e]=i
        #d[copy(e)]=i
    end
    values(d)
end

```

PS  
unlike unique provides the latest index among those that have the same value  
use thie version in case

```julia
julia> function distind(m)
           d=Dict{SubArray{Int64, 1, Matrix{Int64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true},Int}()
           #d=Dict{Array{Int},Int}()
           for (i,e) in enumerate(Iterators.reverse(eachrow(m)))
               d[e]=i
               #d[copy(e)]=i
           end
           values(d)
       end
distind (generic function with 1 method)

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 25, 2024, 4:56pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/6 "2024-01-25T16:56:15Z")

</div>

> [@rocco\_sprmnt21](#):
>
> `Dict{SubArray{Int64, 1, Matrix{Int64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true},Int}()`

OMG!

Perhaps just:

```julia
Dict{Vector{Int}, Int}()

```

---

<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:** [January 25, 2024, 5:55pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/7 "2024-01-25T17:55:54Z")

</div>

I had tried as you say, but it gave me an error which (due to the rush) I attributed to the fact that the type returned by the eacrow() function could not be replaced by array{Int}.  
I take this opportunity to add a different way of obtaining the same result  
senza usare il tipo OMG 😁

Although, sometimes, the measurements say that the OMG type is better

```julia
julia> function distindOMG2(m)
           d=Dict{SubArray{Int64, 1, Matrix{Int64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true},Int}()
           for (i,e) in enumerate(eachrow(m))
               get!(d,e,i)
           end
           values(d)
       end
distindOMG2 (generic function with 1 method)

julia> function distindJustV(m)
           d=Dict{Array{Int},Int}()
           for (i,e) in enumerate(eachrow(m))
               get!(d,e,i)
           end
           values(d)
       end
distindJustV (generic function with 1 method)

julia> @btime distindOMG2($m)
  786.667 ns (7 allocations: 4.38 KiB)
ValueIterator for a Dict{SubArray{Int64, 1, Matrix{Int64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true}, Int64} with 11 entries. Values:    
  2
  4
  8
  1
  14
  20
  16
  7
  10
  5
  3

julia> @btime distindJustV($m)
  2.000 μs (58 allocations: 3.98 KiB)
ValueIterator for a Dict{Array{Int64}, Int64} with 11 entries. Values:   
  2
  4
  8
  1
  14
  20
  16
  7
  10
  5
  3

```

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [January 25, 2024, 6:54pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/8 "2024-01-25T18:54:46Z")

</div>

Instead of writing out the view type, you could use the first element to define it. This should be as efficient:

```julia
julia> function distind2(mat::AbstractMatrix)
         (i,e), rest = Iterators.peel(zip(axes(mat,1), eachrow(mat)))
         d = Dict(e => i)
         for (i,e) in rest
           d[e] = i
         end
         values(d)
       end
distind2 (generic function with 2 methods)

julia> distind2([1 2; 3 4; 3 4] ./ pi) # any eltype
ValueIterator for a Dict{SubArray{Float64, 1, Matrix{Float64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true}, Int64} with 2 entries. Values:
  1
  3

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 25, 2024, 7:29pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/9 "2024-01-25T19:29:21Z")

</div>

This seems to be just as efficient, but simpler:

```julia
function distind3(m)
    d = Dict{eltype(eachrow(m)), Int}()
    for (i,e) in pairs(eachrow(m))
        d[e] = i
    end
    values(d)
end

```

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [January 25, 2024, 7:37pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/10 "2024-01-25T19:37:27Z")

</div>

True, and this allows the empty case `distind3(rand(0,3))` which mine does not.

---

<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:** [January 25, 2024, 9:07pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/11 "2024-01-25T21:07:04Z")

</div>

to squeeze the instructions a little more, a fully functional solution (no for loop)

```julia
function distind4(m)
    values(Dict(zip(eachrow(m),axes(m,1))))
end

```

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [January 25, 2024, 9:32pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/12 "2024-01-25T21:32:58Z")

</div>

Another cool way:

```julia
distind5(M) = first.(unique(last,pairs(eachrow(M))))

```

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [January 25, 2024, 11:07pm UTC](https://discourse.julialang.org/t/get-indices-of-unique-rows-in-2d-array/109208/13 "2024-01-25T23:07:04Z")

</div>

> [@dalarev](#):
>
> Context is I have a list of (x,y,z) coordinates (Mx3 array)

Often it’s more convenient to use a vector of static vectors to represent such data. In this case, it lets you use `unique` in the way you were already familiar with:

```julia
julia> using StaticArrays

julia> A = [1 2; 3 4; 1 2];

julia> B = SVector{2}.(eachrow(A))
3-element Vector{SVector{2, Int64}}:
 [1, 2]
 [3, 4]
 [1, 2]

julia> unique(i -> B[i], eachindex(B))
2-element Vector{Int64}:
 1
 2

```
