I have seen many examples of converting an array of arrays into a matrix, but I would like to go the other way. What I have cobbled together works, but may not be the most elegant or fast solution. I would appreciate any comments and builds.
function sliceMatrix(A)
m, n = size(A)
B = Array{Array{eltype(A), 1}, 1}(undef, m)
for i = 1:m
B[i] = A[i, :]
end
return B
end
Is there a way to pre-allocate the individual arrays inside B?
I don’t think you gain much from preallocating in this situation, but here is one way where I only modified your functions a little bit:
julia> function slicematrix(A::AbstractMatrix{T}) where T
m, n = size(A)
B = Vector{T}[Vector{T}(undef, n) for _ in 1:m]
for i in 1:m
B[i] .= A[i, :]
end
return B
end
slicematrix (generic function with 1 method)
julia> slicematrix(rand(2,3))
2-element Array{Array{Float64,1},1}:
[0.686489, 0.016934, 0.638272]
[0.317802, 0.543907, 0.208549]
but it is probably better and simpler to just define it as:
function slicematrix(A::AbstractMatrix)
return [A[i, :] for i in 1:size(A,1)]
end
Note also that Julia’s Array is column major, so extracting columns (A[:, i]) is much faster than extracting rows (A[i, :]).
While trying this myself, I found a faster solution than the simple suggestion above.
Iterate over the columns with eachcol or eachrow:
A = rand(5,10000)
@btime [c[:] for c in eachcol(A)]
@btime [A[:,c] for c in 1:size(A,2)]
julia>
382.300 μs (20005 allocations: 1.75 MiB)
2.788 ms (38985 allocations: 1.74 MiB)
Note that your benchmarking produced false inferences due to accessing global variables. If you interpolate the variables into the expressions (using $). The results are much more similar.
I also include an even faster version, if you can work with static vectors:
using StaticArrays
A = rand(5,10000)
@btime [c[:] for c in eachcol($A)]
@btime [$A[:,c] for c in 1:size($A,2)]
@btime vec(reinterpret(SVector{size($A,1),eltype($A)},$A))
506.052 μs (20005 allocations: 1.75 MiB)
440.997 μs (10004 allocations: 1.30 MiB)
1.542 μs (11 allocations: 704 bytes)
I think @MatthijsCox approx with eachcol is in fact faster (but still slower than StaticArrays), the problem is how columns are collected.
A = rand(5,10000);
@btime collect(eachcol($A));
@btime [c[:] for c in eachcol($A)];
@btime [$A[:,c] for c in 1:size($A,2)];
[A[:,c] for c in 1:size(A,2)] == collect(eachcol(A))
> julia
96.849 μs (10004 allocations: 547.00 KiB)
481.677 μs (20005 allocations: 1.75 MiB)
413.083 μs (10004 allocations: 1.30 MiB)
true
Note that the latter two create copies, while the first one returns views:
julia> @btime [c[:] for c in eachcol($A)];
535.007 μs (20005 allocations: 1.75 MiB)
julia> @btime [c for c in eachcol($A)];
80.548 μs (10005 allocations: 547.02 KiB)