Null initialisation for a loop that appends vectors

In Matlab, it is common to initialise a loop like this:
x = ; for i = 1:n; x = [x; another numerical row vector (of fixed length L)]; end
This creates a matrix of size [n,L]. It works regardless of chosen length L.

What is the equivalent Julia idiom please? vcat won’t append to an empty value, as far as I can see. I don’t want to have to repeat all the code in the loop to find the first row separately: I just want to append the first row to some sort of null object, if that’s allowed.

It’s a bad pattern both in Matlab and Julia unless you have rather small amounts of data but the key to make it work in Julia is to start with an empty matrix of a compatible size.

julia> x = zeros(0, 5)
0×5 Matrix{Float64}

julia> for _ in 1:3
           x = [x; rand(1, 5)]
       end

julia> x
3×5 Matrix{Float64}:
 0.282795  0.316492  0.385162  0.649601  0.72799
 0.176852  0.16786   0.62178   0.100277  0.296178
 0.564282  0.651074  0.487304  0.71793   0.0336523
1 Like

If you can’t preallocate the array and simply write the entries then I would do something like this:

x = Matrix{Float64}[] # empty Vector{Matrix{Float64}}
for i in 1:10
    if rand() < 0.5 # maybe don't always add a row
        row = rand(1, 5) # generate a row
        push!(x, row) # save it
    end
end
X = reduce(vcat, x) # concatenate all the saved samples into a single Matrix

thanks, I’ll look at that.
I should have mentioned that preallocation is difficult in my application because the loop count n is not known beforehand: the loop exits when certain conditions are met, but n can be quite large. I believe that Julia is much more efficient at appending than Matlab, which made me think that appending without preallocation might be worth trying. But what if n is getting up to 1e7, 1e8 ?

Often such things can be written M = stack(function, iterator), where the function returns data that will become a column or a row of the final matrix. With a do block:

julia> stack(1:5) do i
         [i/2, i/3, i/5]  # this is a column
       end
3×5 Matrix{Float64}:
 0.5       1.0       1.5  2.0      2.5
 0.333333  0.666667  1.0  1.33333  1.66667
 0.2       0.4       0.6  0.8      1.0

julia> stack(1:5; dims=1) do i
         (i/2, i/3, i/5)  # this will become a row
       end
5×3 Matrix{Float64}:
 0.5  0.333333  0.2
 1.0  0.666667  0.4
 1.5  1.0       0.6
 2.0  1.33333   0.8
 2.5  1.66667   1.0

Edit, but this won’t help if the number of iterations isn’t fixed. In that case, push!-ing into some list is probably what you want. This should be more efficient than re-creating the matrix at every step of the loop.

julia> slices = [];  # ideally you provide the type here, T[], with T = typeof(col)

julia> for i in 1:999  # ideally this is all in a function too!
         i > 5 && break
         col = (i/2, i/3, i/5)
         push!(slices, col)
       end

julia> stack(slices)
3×5 Matrix{Float64}:
 0.5       1.0       1.5  2.0      2.5
 0.333333  0.666667  1.0  1.33333  1.66667
 0.2       0.4       0.6  0.8      1.0
1 Like

If anything, I would expect MATLAB has taken pains to make repeatedly adding rows to a matrix vaguely performant (naively, it’s a horrific pattern for data movement). I am quite certain Julia has not. So, without having benchmarked it, I would guess it does better (or at least similarly) to Julia for that pattern.

OK, thanks guys, I need to do some reading about your suggestions. Very much a Julia newbie.
Is it OK not to tick any post as the final answer for the time being?

2 Likes

Sure, it’s common to not select an accepted answer, unless there is a very definitive one. Just leave it open, if you like.