Finding row index of matrix

Hi,
I have two matrices :

b = 
6×2 Array{Int64,2}:
 0  2
 1  4
 0  7
 1  4
 1  5
 2  4

and

a = 
6×2 Array{Int64,2}:
 0  2
 0  7
 1  4
 1  4
 1  5
 2  4

I need to find row index, i of matrix b with respect to a. i.e. a = b(i)

and get output as array: 
1
3
2
5
4

I tried using functions like findall but haven’t got this desired output
Thanks in advance

I will not give you a solution but I will at least share that what you are after is (row) permutation. Either represented by a permutation vector (the one that you call row indices) or a permutation matrix.

For convenience I reenter your matrices here (please next time make it easier for others to help you by putting such code here)

B = [0  2; 1  4; 0  7; 1  4; 1  5; 2  4]
A = [0  2; 0  7; 1  4; 1  4; 1  5; 2  4]

The permutation vector is

p = [1,3,2,4,5,6]

There is a fuction called permute! in Julia, but it only works for vectors and not matrices. We could perhaps reformat the matrix into a vector of row vectors but I will not do it here. Instead, I will form a permutation matrix

julia> using LinearAlgebra

julia> P = 1I(6)[p,:]
6×6 SparseArrays.SparseMatrixCSC{Int64, Int64} with 6 stored entries:
 1  ⋅  ⋅  ⋅  ⋅  ⋅
 ⋅  ⋅  1  ⋅  ⋅  ⋅
 ⋅  1  ⋅  ⋅  ⋅  ⋅
 ⋅  ⋅  ⋅  1  ⋅  ⋅
 ⋅  ⋅  ⋅  ⋅  1  ⋅
 ⋅  ⋅  ⋅  ⋅  ⋅  1

and use it to permute the rows of the matrix B just by premultiplication.

julia> A == P*B
true

Well, I did not help solve the problem (I did not show how to find the vector p or the matrix P, I only interpreted them) but at least you may have another keyword to search for. Your are trying to find a permutation matrix (or the corresponding vector) to transform one matrix into another by premultiplication. I am afraid you would just have to loop over the rows of the matrices.

3 Likes

Thanks

This one almost works, although it does not increment for duplicate row entries:

map(eachrow(b)) do r
       findfirst(i->view(a,i,:)==r, 1:size(a,1))
end
6-element Vector{Int64}:
 1
 3
 2
 3
 5
 6

To fix this for repeated elements, something like this works:

a = [0 2; 0 7; 1 4; 1 4; 1 5; 2 4]
b = [0 2; 1 4; 0 7; 1 4; 1 5; 2 4]

# Build up a dict mapping each row to the row numbers where the row occurs
l = Dict{Vector{Int}, Vector{Int}}()
foreach(1:size(a,1)) do i
    r = a[i,:]
    if haskey(l,r) 
        push!(l[r], i)
    else 
        l[r] = [i]
    end
end
# And collect the values according to their occurences
map(eachrow(b)) do r
    popfirst!(l[r])
end
6-element Vector{Int64}:
 1
 3
 2
 4
 5
 6
4 Likes

Another take:

function findrowindex(a,b)
    c = fill(0,size(a,1))
    for i in axes(a,1)
        for j in axes(b,1)
            @views if (b[j,:] == a[i,:]) & !(j in c)
                c[i] = j
                @goto outerloop
            end
        end
        @label outerloop
    end
    return c
end

NB: the goto is not needed but aims at speeding up function

c = findrowindex(a,b)
6-element Vector{Int64}:
 1
 3
 2
 4
 5
 6
b[c,:] == a     # true
1 Like

Is this correct? The original question has 6 rows, but a 5-vector answer. Some rows are repeated.

My guess from the words was indexin, and possibly unique, but…

julia> q = indexin(collect(eachrow(A)), collect(eachrow(B)))
6-element Vector{Union{Nothing, Int64}}:
 1
 3
 2
 2
 5
 6

julia> A == B[q, :]
true

julia> res = [1, 3, 2, 5, 4];  # from question

julia> B[res, :]  # not the same shape as A
5×2 Matrix{Int64}:
 0  2
 0  7
 1  4
 1  5
 1  4

julia> B[unique(q), :]
5×2 Matrix{Int64}:
 0  2
 0  7
 1  4
 1  5
 2  4

julia> indexin(collect(eachrow(B)), collect(eachrow(A))) # reversed, matches @fabiangans's map(eachrow(b))
6-element Vector{Union{Nothing, Int64}}:
 1
 3
 2
 3
 5
 6
2 Likes