# Destructuring and broadcast

**URL:** <https://discourse.julialang.org/t/destructuring-and-broadcast/5672>\
**Category:** General Usage\
**Tags:** question\
**Created:** [September 1, 2017, 12:45pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672 "2017-09-01T12:45:51Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 1, 2017, 12:45pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/1 "2017-09-01T12:45:51Z")

</div>

If I want to broadcast a function that returns a tuple, is there a simple way to “broadcast” the left hand side destructuring?

```julia
a = 1:10
b = 11:20

transform(a, b) = a+b, a*b, a-b # MWE, the real one is more compicated

## want something like (syntax of course does not work)
@. x, y, z = transform(a, b)

## of course I can do
w = transform.(a,b)
x = first.(w)
y = (v->v[2]).(w)
z = last.(w)

```

---

<div class="post-metadata">

**Author:** ![NickNack](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nicknack/32/1792_2.png) [@NickNack](https://discourse.julialang.org/u/NickNack)\
**Post date:** [September 1, 2017, 1:46pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/2 "2017-09-01T13:46:00Z")

</div>

I don’t know about simple, but I had the same problem and came up with this oneliner for creating NTuples:

```julia
x,y,z = collect(zip(transform.(a,b)...))

```

If you absolutely need Vectors then add another collect:

```julia
x,y,z = collect.(collect(zip(transform.(a,b)...)))

```

But I’m still a newbie, so I’m sure there’s a better way. I’m curious to see what the pros come up with.

---

<div class="post-metadata">

**Author:** ![spalato](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/spalato/32/3723_2.png) [@spalato](https://discourse.julialang.org/u/spalato)\
**Post date:** [October 15, 2017, 3:10am UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/3 "2017-10-15T03:10:22Z")

</div>

Hi,

I have a similar issue: I don’t know how to obtain a tuple of arrays instead of an array of tuples.

The answer by @NickNack works for simple cases, but loses track of resulting shape when the broadcast results in more than one dimension.

```julia
# compute on a 2d grid
x1 = reshape(1:5, (5,1)) 
x2 = reshape(6:11, (1,6))
typeof(collect(zip(transform.(x1,x2)...))) # Array{NTuple{30,Int64},1}

```

This result is different from the solution by @Tamas_Papp, which correctly preserves the shape of the resulting arrays.

Coming from python/numpy, I am used to this situation resulting in tuple of arrays instead of array of tuples. Anybody knows a way to obtain similar behavior in julia?

The equivalent numpy code:

```python
import numpy as np

def transform(a, b):
    return a+b, a*b, a-b

x1 = np.arange(1, 6).reshape((5,1))
x2 = np.arange(6, 12).reshape((1,6))
u, v, w = transform(x1, x2)

```

Potentially related:  
[https://github.com/JuliaLang/julia/issues/13942](https://github.com/JuliaLang/julia/issues/13942)

None of the proposed solutions seem to work here, upon a very superficial quick try.

---

<div class="post-metadata">

**Author:** ![simonbyrne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simonbyrne/32/19_2.png) [@simonbyrne](https://discourse.julialang.org/u/simonbyrne)\
**Post date:** [October 12, 2018, 11:56pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/4 "2018-10-12T23:56:22Z")

</div>

Relevant issue: [https://github.com/JuliaLang/julia/issues/22129](https://github.com/JuliaLang/julia/issues/22129)

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [October 13, 2018, 7:07am UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/5 "2018-10-13T07:07:17Z")

</div>

In v0.6, I used StructsOfArrays to do broadcasting with tuple output:

```julia
using StructsOfArrays

T = Float64
TV = Vector{Float64}

a = zeros(T, 10); b = copy(a)
s = StructOfArrays{NTuple{2,T}, 1, Tuple{TV, TV}}((a, b))

f(a, b) = (a + b, a * b)

s .= f.(1:10, 1:10)

```

A macro for the above should be simple enough. Figuring out `T` and `TV` and handling the case where `a` and `b` are not already allocated are the main challenges I can see.

---

<div class="post-metadata">

**Author:** ![sairus7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sairus7/32/10816_2.png) [@sairus7](https://discourse.julialang.org/u/sairus7)\
**Post date:** [October 13, 2018, 12:33pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/6 "2018-10-13T12:33:59Z")

</div>

> [@Tamas\_Papp](#):
>
> transform(a, b) = a+b, a\*b, a-b

Why not use dot-operations inside a function? As far as I can see, it works as well for scalars.

```
a_ = collect(a)
b_ = collect(b)
transform(a, b) = a .+ b, a .* b, a .- b

x, y, z = transform(a_, b_)

```

Also, if there are only `+`, `-` and `*` operations, they probably can be redefined as dot-wise for properly-sized `AbstractArrays` ?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [October 13, 2018, 3:25pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/7 "2018-10-13T15:25:57Z")

</div>

> [@sairus7](#):
>
> Why not use dot-operations inside a function?

Assume that the transformation is a black box, eg because it involves a costly, large intermediate result that you don’t want to allocate. Eg

```julia
function transform(a, b)
    m = g(a, b)
    make_x(m), make_y(m)
end

```

where `g` is costly and `m` is large.

---

<div class="post-metadata">

**Author:** ![AlexS12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexs12/32/24033_2.png) [@AlexS12](https://discourse.julialang.org/u/AlexS12)\
**Post date:** [April 29, 2021, 7:31pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/8 "2021-04-29T19:31:08Z")

</div>

It seems that four years after I am finding the exact same issue. Is there a better or preferred solution now?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [April 30, 2021, 1:39pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/9 "2021-04-30T13:39:34Z")

</div>

`LazyRow` + `StructArray` would be my go to solution now.

[https://github.com/JuliaArrays/StructArrays.jl](https://github.com/JuliaArrays/StructArrays.jl)

---

<div class="post-metadata">

**Author:** ![AlexS12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexs12/32/24033_2.png) [@AlexS12](https://discourse.julialang.org/u/AlexS12)\
**Post date:** [May 2, 2021, 9:28am UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/10 "2021-05-02T09:28:43Z")

</div>

Thanks, @Tamas_Papp I have no previous experience with StructArrays. I expected something like this to work:

```julia
julia> using StructArrays

julia> a = 1:10
1:10

julia> b = 11:20
11:20

julia> transform(a, b) = a+b, a*b, a-b
transform (generic function with 1 method)

x, y, z = StructArray(transform.(a, b))
10-element StructArray(::Vector{Int64}, ::Vector{Int64}, ::Vector{Int64}) with eltype Tuple{Int64, Int64, Int64}:
 (12, 11, -10)
 (14, 24, -10)
 (16, 39, -10)
 (18, 56, -10)
 (20, 75, -10)
 (22, 96, -10)
 (24, 119, -10)
 (26, 144, -10)
 (28, 171, -10)
 (30, 200, -10)

julia> x # Get the first row here instead of first column (which I want)
(12, 11, -10)

```

The only option I can find now is:

```julia
julia> w = StructArray(transform.(a, b))
10-element StructArray(::Vector{Int64}, ::Vector{Int64}, ::Vector{Int64}) with eltype Tuple{Int64, Int64, Int64}:
 (12, 11, -10)
 (14, 24, -10)
 (16, 39, -10)
 (18, 56, -10)
 (20, 75, -10)
 (22, 96, -10)
 (24, 119, -10)
 (26, 144, -10)
 (28, 171, -10)
 (30, 200, -10)

julia> x = getproperty(w, 1)
10-element Vector{Int64}:
 12
 14
 16
 18
 20
 22
 24
 26
 28
 30

```

Which is not so different from this approach without StructArrays:

```julia
julia> w = transform.(a, b)
10-element Vector{Tuple{Int64, Int64, Int64}}:
 (12, 11, -10)
 (14, 24, -10)
 (16, 39, -10)
 (18, 56, -10)
 (20, 75, -10)
 (22, 96, -10)
 (24, 119, -10)
 (26, 144, -10)
 (28, 171, -10)
 (30, 200, -10)

julia> x = getindex.(w, 1)
10-element Vector{Int64}:
 12
 14
 16
 18
 20
 22
 24
 26
 28
 30

```

Am I missing something? What I am looking for is a “direct way” to unpack the columns of a broadcasted function. Something like `@. x, y, z = transform(a, b)` which you mentioned at the beginning of the this post.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [May 2, 2021, 5:57pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/11 "2021-05-02T17:57:01Z")

</div>

You can use `components()`:

```julia
using StructArrays
a, b = 1:10, 11:20
transform(a, b) = a+b, a*b, a-b
w = StructArray(transform.(a, b))
x, y, z = StructArrays.components(w)

```

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [May 2, 2021, 6:01pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/12 "2021-05-02T18:01:42Z")

</div>

I asked a related question at the Tables.jl repo. It looks like the compiler should be smart enough to make this work even if you have an intermediate collection of tuples. [Does Tables have the infrastructure for a performant map that returns vectors of tuples? · Issue #237 · JuliaData/Tables.jl · GitHub](https://github.com/JuliaData/Tables.jl/issues/237)

---

<div class="post-metadata">

**Author:** ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)\
**Post date:** [May 2, 2021, 6:49pm UTC](https://discourse.julialang.org/t/destructuring-and-broadcast/5672/13 "2021-05-02T18:49:04Z")

</div>

> [@rafael.guerra](#):
>
> ```julia
> using StructArrays
> a, b = 1:10, 11:20
> transform(a, b) = a+b, a*b, a-b
> w = StructArray(transform.(a, b))
> x, y, z = StructArrays.components(w)
> 
> ```

As a tiny improvement, one can also do

```julia
w = StructArray(Iterators.map(transform, a, b))

```

so that the intermediate vector of structs is not created at all, but one only allocates the columns that will be used later. I think a similar trick can be done with `broadcast`, it should probably be something like

```julia
w = StructArray(Broadcast.Broadcasted(transform, (a, b)))

```

This could maybe even justify defining a small helper function in StructArrays, like

```julia
unzip(iter) = components(StructArray(iter))
unzipwith(f, args...) = unzip(Iterators.map(f, args...)) # is this the correct name?

```

though it should probably not be exported, because the name is very generic.
