Iterating over the columns of a matrix

I want to iterate a function whose argument is a vector. The vectors to iterate on are the columns of a matrix. I was “slicing” the matrix into columns following Converting a matrix into an array of arrays and then iterate over the new array whose entries are the vectors I want.

I think it is not optimal and that is my first question: If all I want is to iterate over the columns of a matrix, then shouldn’t I define an iterator (instead of copying the whole matrix)?
So, I came up with the following code which does the trick, but I am not sure whether this is the right way to define such iterator (e.g. are the last two lines strictly necessary? defining the length gives me problems with the length function…)

struct AbstractMatrixColumn
    M::AbstractMatrix
end

function Base.iterate(M::AbstractMatrixColumn)
    state = 1
    return Base.iterate(M,state)
end

function Base.iterate(M::AbstractMatrixColumn, state)
    if state > size(M.M,2)
        next = nothing
    else
        next = M.M[:,state], state+1
    end
    return  next
end

Base.length(M::AbstractMatrixColumn) = size(M.M,2)
Base.eltype(M::AbstractMatrixColumn) = typeof(M.M[:,1])

Coming back to Converting a matricx into an array of arrays, now we can use this iterator to collect the columns of a matrix M with collect(AbstractMatrixColumns(M)), but it is much slower. Is it supposed to be or it is a problem with my implementation?

function slicematrix_column(M::AbstractMatrix{T}) where T
    return [M[:,i] for i in 1:size(M,2)]
end

n = 1000;
N = rand(n,n);
@btime collect(AbstractMatrixColumn($N));
@btime slicematrix_column($N);

> julia
  2.083 ms (6945 allocations: 7.87 MiB)
  1.329 ms (1003 allocations: 7.76 MiB)
2 Likes

This is what eachcol, eachrow and eachslice are for:

julia> A = rand(0:9, 4,5)
4×5 Array{Int64,2}:
 9  2  8  7  6
 2  4  9  0  6
 4  4  4  5  3
 3  0  7  3  1

julia> for col in eachcol(A)
       println(col)
       end
[9, 2, 4, 3]
[2, 4, 4, 0]
[8, 9, 4, 7]
[7, 0, 5, 3]
[6, 6, 3, 1]

These iterators return views, in case that’s relevant, while your code makes copies.

7 Likes

BTW, a performance issue in your code is that you have an abstract type signature in the field of AbstractMatrixColumn. If you want to experiment furter with this, you should make that field concrete or parametric.

Thank you so much @DNF. Yes, I want to experiment further :smile: