How to convert an array of arrays into a matrix?

Viewed 303

I can't find an answer to this simple question.

I have the following:

A(a,j)=[a*j*i*k for i in 1:2, k in 1:2];

B=[A(a,j) for a in 1:2, j in 1:2];

B is a an array of arrays: 2×2 Array{Array{Int64,2},2}. This is useful to easily access the subarrays with indices (e.g., B[2,1]). However, I also need to convert B to a 4 by 4 matrix. I tried hcat(B...) but that yields a 2 by 8 matrix, and other options are worse (e.g., cat(Test2...;dims=(2,1))).

Is there an efficient way of writing B as a matrix while keeping the ability to easily access its subarrays, especially as B gets very large?

2 Answers

Do you want this:

julia> hvcat(size(B,1), B...)
4×4 Array{Int64,2}:
 1  2  2   4
 2  4  4   8
 2  4  4   8
 4  8  8  16

or without defining B:

julia> hvcat(2, (A(a,j) for a in 1:2, j in 1:2)...)
4×4 Array{Int64,2}:
 1  2  2   4
 2  4  4   8
 2  4  4   8
 4  8  8  16

What about

B = reduce(hcat, reduce(vcat, A(a,j) for a in 1:2) for j in 1:2)

EDIT: Actually this is very slow, I would recommend making a function, e.g.,

function buildB(A, n)
    A0 = A(1,1)
    nA = size(A0, 1)
    B = Array{eltype(A0),2}(undef, n * nA, n * nA)
    for a in 1:n, j in 1:n
        B[(a-1)*nA .+ (1:nA), (j-1)*nA .+ (1:nA)] .= A(a,j)
    end
    return B
end

or maybe consider a package like BlockArrays.jl?


EDIT 2 This is an example with BlockArrays.jl:

using BlockArrays
function blockarrays(A, n)
    A0 = A(1,1)
    nA = size(A0, 1)
    B = BlockArray{eltype(A0)}(undef_blocks, fill(nA,n), fill(nA,n))
    for a in 1:n, j in 1:n
        setblock!(B, A(a,j), a, j)
    end
    return B
end

which should do what you want:

julia> B = blockarrays(A, 2)
2×2-blocked 4×4 BlockArray{Int64,2}:
 1  2  │  2   4
 2  4  │  4   8
 ──────┼───────
 2  4  │  4   8
 4  8  │  8  16

julia> getblock(B, 1, 2)
2×2 Array{Int64,2}:
 2  4
 4  8

julia> B[4,2]
8
Related