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[1])])
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!