# Matrix to array of tuples: Avoiding many small allocations

How do I convert a matrix to an array of tuples while avoiding many small allocations in a loop? My current code is

``````function matrixtotuple(x::AbstractMatrix{T}) where T
r,c = size(x)
pts = Vector{Tuple}(undef,r)
@time @inbounds for i in 1:r
pts[i] = Tuple(x[i,:])
end
return pts
end
``````

For a 20x2 matrix, the loop does 100 allocations which means its 5 allocations per row. For a large matrix with millions of entries, it will perform many small allocations thus slowing down my code. Is there a better way to do this operation without allocating in the loop?

It’s probably easier to just do

``````tuple.(eachcol(m)...)
``````

With StructArrays you could create a custom array type such that indexing into it gives you tuples, while reusing memory, which can be useful if the original array is big:

``````julia> using StructArrays

julia> m = rand(20, 2);

julia> sa = StructArray(Tuple(eachcol(m)))
20-element StructArray(view(::Array{Float64,2}, :, 1), view(::Array{Float64,2}, :, 2)) with eltype Tuple{Float64,Float64}:
(0.4970326273287038, 0.21143138008431217)
(0.29962208131086276, 0.061704834464211045)
(0.4966772487171329, 0.9175385362922233)
(0.527788713877285, 0.7280621891438683)
(0.6150731201744135, 0.00070954809832946)
(0.9146189735972257, 0.5957334145094078)
(0.6407960691283592, 0.44134204020165546)
(0.6772847683943304, 0.0652426344276058)
(0.6124967642056414, 0.09899733105729025)
(0.52764483080016, 0.22016424658251132)
(0.07246528707313882, 0.7648818239756578)
(0.6289503443358524, 0.8154583933386323)
(0.718739296080896, 0.776853087938548)
(0.22946316921846432, 0.1630589657899728)
(0.9242116187812148, 0.7729709003381926)
(0.35424126211091633, 0.7732465640412218)
(0.786801141532484, 0.9334757632322519)
(0.18693070616317198, 0.20233848154960543)
(0.2922497465234608, 0.06163461119766822)
(0.8558830208857984, 0.21699499637318542)
``````
3 Likes

The StructArray is just what I need. For a 20x2 matrix, this is the benchmark:

``````x = rand(20,2)
@btime y = matrixtotuple(\$x);
7.025 μs (101 allocations: 5.23 KiB)

@btime tuple.(eachcol(\$x)...);
772.165 ns (9 allocations: 656 bytes)

@btime sa = StructArray(Tuple(eachcol(\$x)));
384.724 ns (7 allocations: 288 bytes)
``````