Concatenating matrices


#1

I have a list of matrices passed into a function. I want to vertically concatenate them into a single matrix. I used to be able to do this:

foo = [[1 2; 3 4; 5 6], [7 8; 9 10; 11 12]]
A = []
for m in foo
    A = [A; m]
end

which, ok, is inefficient, but in this particular code I only have to do it once so I don’t care. And it has the advantage of being fairly readable and compact.

As of 1.0, this throws an error:

ERROR: DimensionMismatch("All inputs to vcat should have the same number of columns")

Actually, in the REPL the error is different:

ERROR: UndefVarError: A not defined

The preferred idiom appears to be something along the lines of:

foo = [[1 2; 3 4; 5 6], [7 8; 9 10; 11 12]]
A = []
for m in foo
    append!(A, m)
end
A = reshape(A, :, size(foo[1], 2))

…because append! doesn’t preserve the shape of multidimensional arrays. This is ugly. And it doesn’t work if foo is empty, or if the first element in foo is one-dimensional or if the elements in foo are scalars. Which, of course, means that now I have to write lots of error checking code, making this even uglier.

In this particular case I’d gladly trade efficiency for compactness. Is there a better way to do this?


#2

Does this accomplish what you want?

julia> vcat(foo...)
6×2 Array{Int64,2}:
  1   2
  3   4
  5   6
  7   8
  9  10
 11  12

The performant idiom for this is reduce(vcat, foo), which is efficient due to a specialization of reduce for vcat that avoids unnecessary intermediate allocations.


#3

Huh. Yes, that’s brilliant.


#4

I have a vague memory of Stefan karpinski mentioning in a post somewhere that splatting is not the best solution if the input list is long since it effectively results in high-dimensional multiple dispatch. Not sure if this still applies to v1.0 but would be interested to find out since I use this syntax in my code quite a bit (and I also have a dedicated function for long list inputs that preallocates the output matrix and then assigns the inputs to it sequentially)