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?
Hopefully the question is clear, please ask otherwise.
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