How to efficiently create a vector from a matrix comprehensions?


#1

Since v0.5 comprehensions are shape-preserving (https://github.com/JuliaLang/julia/pull/16622), so

m = [x for x in [1 2; 3 4]]

results in a matrix.

How should one, using a comprehension, create a vector instead? Something that better reflects a traditional for loop:

v = Int[]
for x in [1 2; 3 4]
    push!(v, x)
end

Preferably in an efficient way, with no temporaries.


#2

m = [x for x in vec([1 2; 3 4])]? vec just uses a view and does’t copy.


#3

It doesn’t seem so:

julia> typeof(vec([1 2; 3 4]))
Array{Int64,1}

#4

That’s not testing anything. Arrays are views too.

julia> const v = [1 2;3 4]
2×2 Array{Int64,2}:
 1  2
 3  4

julia> @time vec(v)
  0.000001 seconds (6 allocations: 240 bytes)
4-element Array{Int64,1}:
 1
 3
 2
 4

julia> const w = [1 2 3 4 5 6;3 4 7 7 8 9]
2×6 Array{Int64,2}:
 1  2  3  4  5  6
 3  4  7  7  8  9

julia> @time vec(w)
  0.000002 seconds (6 allocations: 240 bytes)
12-element Array{Int64,1}:
 1
 3
 2
 4
 3
 7
 4
 7
 5
 8
 6
 9

julia> z = vec(w)
12-element Array{Int64,1}:
 1
 3
 2
 4
 3
 7
 4
 7
 5
 8
 6
 9

julia> z[1] = 10
10

julia> w
2×6 Array{Int64,2}:
 10  2  3  4  5  6
  3  4  7  7  8  9


No allocations, just the allocation of the view which is constant 240 bytes. The array just tells it how to index. Once Tim Holy explained that, the magic went away.


#5

Wow! That is something completely new to me! And, at a first sight, this kind of hidden aliasing seems a little bit too dangerous…

Thanks @ChrisRackauckas.

By the way, besides that comment by @tim.holy, is there any documentation on this?


#6

vec really doesn’t copy:

julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
 1  2
 3  4

julia> v = vec(A)
4-element Array{Int64,1}:
 1
 3
 2
 4

julia> A[1,1] = 11
11

julia> v
4-element Array{Int64,1}:
 11
  3
  2
  4