# How to do "((1,2), 3) .+ ((1,2), 3)"?

TL;DR: How can we “broadcast” a function over several nested Tuples such as `((1,2), 3) .+ ((1,2), 3)`?

So, say I have several objects `x_i` that are tuples of tuples and numbers (each of the tuples itself a tuple of tuples and numbers). For example `x_1 = ((1,2), 3)` or `x_1 = (1, (2,3,(3,4)), (2,3))`, etc… Now assume all `x_i` have the same structure, just different numbers. How can we apply a function `f` elementwise recursively, i.e. to arbitrary Tuple depth to a collection of `x_i`?

Currently `((1,2), 3) .+ ((1,2), 3)` fails because it does `+` only at the first level, and tuples themselves cannot be summed. I know broadcast is what it is, and it’s not exactly this, so I’m looking for something different. I’d like it to yield `((1+1, 2+2), 3+3)` etc. Is this possible? Can we make it work it with arbitrary tuple nesting?

If you’re doing math with tuples, consider using the `StaticArrays` packages instead. It gives you immutable arrays with arithmetic and linear algebra defined on them.

That said:

``````_f(x, y) = x + y
_f(x::Tuple, y::Tuple) = _f.(x, y)
``````
``````julia> t1 = ((1,2), (3, (5,6)), (7, 8), 9);

julia> _f(t1, t1)
((2, 4), (6, (10, 12)), (14, 16), 18)
``````

For numbers and Tuples of numbers, the above will work. Use at your own risk!

3 Likes

Here’s a crazy hack:

``````julia> ⊕(x, y) = x .⊕ y
⊕(x::Number, y::Number) = x + y
⊕ (generic function with 2 methods)

julia> ((1, 2), 3) .⊕ ((4, 5), 6)
((5, 7), 9)
``````

It may behave suprisingly with unmatched tuple lengths and will stack-overflow with non-number-containing things.

4 Likes

Thanks! Yeah, I was rather looking for a solution more like broadcast or map that does not require to touch the methods of the function f. But I guess these options are probably the simplest

If you only need to go down one level, you could just broadcast a broadcasted operator. Hopefully someday soon you’ll be able to do `(.+).(((1, 2), 3), ((4, 5), 6))` or `broadcast(.+, ((1, 2), 3), ((4, 5), 6))`, but until then you could do:

``````julia> broadcast((args...)->(+).(args...), ((1, 2), 3), ((4, 5), 6))
((5, 7), 9)
``````
4 Likes

Very nice! I think I’ll mark @tomerarnon’s reply as solution, thanks again to both.

1 Like