# Broadcast over a multiple output function and receive a Tuple of Arrays

Is there a convenient way to broadcast over a function that produces multiple outputs and receive a tuple of arrays instead of an array of tuples?

For example, with the `sincos` function, I get the following output upon broadcast:

``````julia> sincos.(2:4)
3-element Vector{Tuple{Float64, Float64}}:
(0.9092974268256817, -0.4161468365471424)
(0.1411200080598672, -0.9899924966004454)
(-0.7568024953079282, -0.6536436208636119)
``````

but what I want is:

``````([0.9092974268256817, 0.1411200080598672, -0.7568024953079282], [-0.4161468365471424, -0.9899924966004454, -0.6536436208636119])
``````

The ugly solution I though of would be to do

``````let a = sincos.(2:4)
Tuple([[b[i] for b in a] for i in eachindex(a)])
end
``````

but this has way too much allocation overhead.

(I know for this particular example I could do `(sin.(2:4), cos.(2:4))`, but I am asking for functions in general, assuming there are no separate `sin` and `cos` methods. Ultimately, I would like to do something along the lines of `s, c = sincos.(2:4)` where `s == sin.(2:4)` and `c == cos.(2:4)`)

Here’s some code I use for re-packing data:

``````function repack(x::AbstractArray{T}) where T<:Tuple
# turn Array{Tuple{T1,T2...}} to Tuple{Array{T1},Array{T2},...}
fT = ntuple(i->fieldtype(T,i),fieldcount(T)) # fieldtypes(T) would be the obvious choice but was type-unstable when I tried
arrs = similar.(Ref(x),fT)
for i in eachindex(x,arrs...)
@inbounds setindex!.(arrs,x[i],Ref(i))
end
return arrs
end
function repack(x::AbstractArray{NamedTuple{N,T}}) where {N,T<:Tuple}
# turn Array{NamedTuple{N,Tuple{T1,T2...}}} to NamedTuple{N,Tuple{Array{T1},Array{T2},...}}
fT = ntuple(i->fieldtype(T,i),fieldcount(T)) # fieldtypes(T) would be the obvious choice but was type-unstable when I tried
arrs = similar.(Ref(x),fT)
for i in eachindex(x,arrs...)
@inbounds setindex!.(arrs,Tuple(x[i]),Ref(i))
end
return NamedTuple{N}(arrs)
end
``````

But this ultimately still requires extra allocations over what could be a variant of `map` that returns tuples-of-arrays rather than arrays-of-tuples. You can certainly achieve this with preallocation and a loop, but that’s only nice if you know the number and types of outputs of your function (which can be annoying to determine programmatically – `map` and `broadcast` are so nice because they don’t require you to do this manually). Maybe someone will eventually implement this `map` variant, but it doesn’t exist yet.

You can also look into `StructArrays.jl`, which may have some utilities for this sort of situation.

1 Like

One more option:

``````using SplitApplyCombine
invert(sincos.(2:4))
``````
2 Likes

Wow, this package is exactly what I was looking for. Thanks!