Inplace conversion of a (m,n)-array into an m-element array

Hi everyone,

I’m new to Julia, comming from Python. I was a bit confused when defining an array as a list of lists in Python, I noticed that it isn’t an array of size(m,n).
I searched the WEB and here, for an inplace conversion of an array of size (m,n) to an m-element array, but couldn’t find any example/reference. Is such a conversion possible?
Example, if I have an array:

arr =  rand(1:15, (3,4))
3×4 Array{Int64,2}:
  6   8   8  13
  4   3  14   6
 14  13   1  12    

I need to convert it inplace into:

[[6, 8, 8, 13],
[4, 3, 14, 6],
[14, 13, 1, 12]]

At the moment I defined the associated m-element array by:

elarr = [arr[k, :] for k in 1:m]    

but for a big m and n it is memory consuming to have both arr and elarr defined.

Julia is column-major, so it’ll be faster to flip your array’s indices and use column-wise slices. Try collect(eachcol(arr)), or eachrow if you really need the rows for some reason.

julia> arr =  rand(1:15, (3,4))
3×4 Array{Int64,2}:
 9  14   9  1
 5   8  13  5
 4  13  15  4

julia> collect(eachcol(arr))
4-element Array{SubArray{Int64,1,Array{Int64,2},Tuple{Base.Slice{Base.OneTo{Int64}},Int64},true},1}:
 [9, 5, 4]
 [14, 8, 13]
 [9, 13, 15]
 [1, 5, 4]
4 Likes

If you really need it to be in-place (meaning, sharing the same data in RAM), then you should use reinterpret in conjunction with StaticArrays.jl:

julia> arr =  rand(1:15, (3,4))
3×4 Matrix{Int64}:
  2  8  14  14
 11  9   6   9
  6  3   5  12

julia> using StaticArrays

julia> av1 = reinterpret(SVector{3,Int}, arr)
1×4 reinterpret(SVector{3, Int64}, ::Matrix{Int64}):
 [2, 11, 6]  [8, 9, 3]  [14, 6, 5]  [14, 9, 12]

Because Julia is column-major, each column of arr has been turned into a vector. You specify the column size as the first parameter to SVector.

On the not-yet-released Julia 1.6, you also have the option to simultaneously reshape into a vector:

julia> av2 = reinterpret(reshape, SVector{3,Int}, arr)     # requires Julia 1.6
4-element reinterpret(reshape, SVector{3, Int64}, ::Matrix{Int64}) with eltype SVector{3, Int64}:
 [2, 11, 6]
 [8, 9, 3]
 [14, 6, 5]
 [14, 9, 12]
6 Likes

My eachcol solution should be in-place, unless there’s some nuance I’m missing:

julia> collect(eachcol(arr))[1][1] = 100
100

julia> arr
3×4 Array{Int64,2}:
 100  14   9  1
   5   8  13  5
   4  13  15  4
1 Like

I think that you are right, but in versions before Julia 1.5 your solution may lead to more allocations (because views may allocate and your alternative generate a view for each column).

@tim.holy

Thank you for your suggestion. I have to dig deeper into StaticArrays, because I’m only 7 days old with Julia. :slight_smile:

You’re right, thanks for the correction. Some people use in-place to mean “no allocation” but your definition is really the right one.

2 Likes