# Idiomatic way to write element-wise combination of array of arrays?

I was wondering how others would construct a combination of the product of two nested arrays?

Example and my approach:

``````a = [[1,2,3],[2,3,4]]
b = [[1,1,1],[0,0,0]]

# want [[1,2,3],[0,0,0]]

z = []
for (i,x) in enumerate(a)
z = append!(z,[x .* b[i]])
end
z
``````

returns:

``````2-element Array{Any,1}:
[1, 2, 3]
[0, 0, 0]
``````

I feel like my approach is a little clunky

Multiple dispatch is pretty cool:

`````` import Base.*

*(x::Array{Array{Int64,1},1}, y::Array{Array{Int64,1},1}) = [x_k .* y_k for (x_k,y_k) in zip(x,y)]

a = [[1,2,3],[2,3,4]]
b = [[1,1,1],[0,0,0]]

a*b
2-element Array{Array{Int64,1},1}:
[1, 2, 3]
[0, 0, 0]
``````
2 Likes

``````julia> broadcast.(*, a, b)
2-element Array{Array{Int64,1},1}:
[1, 2, 3]
[0, 0, 0]
``````
5 Likes

This is also possible.

``````julia> ((x,y)->x.*y).(a,b)
2-element Array{Array{Int64,1},1}:
[1, 2, 3]
[0, 0, 0]
``````
2 Likes

Or define a broadcastable `*â‚Š` function like this:

``````julia> *â‚Š(a, b) = a .* b
*â‚Š (generic function with 1 method)

julia> a .*â‚Š b
2-element Array{Array{Int64,1},1}:
[1, 2, 3]
[0, 0, 0]
``````
2 Likes

Note that my solution generalize well to arbitrary â€śdepthsâ€ť:

``````julia> aa = [a, a]
2-element Array{Array{Array{Int64,1},1},1}:
[[1, 2, 3], [2, 3, 4]]
[[1, 2, 3], [2, 3, 4]]

julia> ab = [a, b]
2-element Array{Array{Array{Int64,1},1},1}:
[[1, 2, 3], [2, 3, 4]]
[[1, 1, 1], [0, 0, 0]]

2-element Array{Array{Array{Int64,1},1},1}:
[[1, 4, 9], [4, 9, 16]]
[[1, 2, 3], [0, 0, 0]]
``````
1 Like

Random thought:
Could it be possible to define `(f.)` to be a function such that `(f.)(args...; kwargs...) = f.(args...; kwargs...)`? This way for nested broadcast one would do `(f.).(args...; kwargs...)`

Iâ€™m completely ignorant about the `broadcast` implementation and its subtleties, so this may be complete nonsense, but I became curious as the issue of multiplying nested arrays has been coming up occasionally.

1 Like

Random thought:
Could it be possible to define `(f.)` to be a function such that `(f.)(args...; kwargs...) = f.(args...; kwargs...)` ? This way for nested broadcast one would do `(f.).(args...; kwargs...)`

This came up recently on Slack and @StefanKarpinski thought it was a possibility.

If you want a shorthand notation, maybe by abusing the exponentiation/power-like symbolâ€¦

``````julia> â†‘Âą(f, args) = broadcast(f, args...)
â†‘Â˛(f, args) = â†‘Âą(broadcast, (f, args...))
â†‘Âł(f, args) = â†‘Â˛(broadcast, (f, args...));

julia> divâ†‘Âą([1], [2])
1-element Array{Int64,1}:
0

julia> divâ†‘Â˛(b, a)
2-element Array{Array{Int64,1},1}:
[1, 0, 0]
[0, 0, 0]

julia> divâ†‘Âł(ab, aa)
2-element Array{Array{Array{Int64,1},1},1}:
[[1, 1, 1], [1, 1, 1]]
[[1, 0, 0], [0, 0, 0]]
``````

More generally, you can recursively define this broadcast up to any depth n like this

``````julia> function rebroadcast(f,n,args...)
end
rebroadcast (generic function with 1 method)

1-element Array{Int64,1}:
0

2-element Array{Array{Int64,1},1}:
[1, 0, 0]
[0, 0, 0]

2-element Array{Array{Array{Int64,1},1},1}:
[[1, 1, 1], [1, 1, 1]]
[[1, 0, 0], [0, 0, 0]]
``````
1 Like

Sorry to bring this up now, but I think there are three more dots `...` missing there. This beautiful function should read:

``````julia> function rebroadcast(f,n,args...)
end
rebroadcast (generic function with 1 method)

julia> a = [[1,2,3],[2,3,4]]
2-element Array{Array{Int64,1},1}:
[1, 2, 3]
[2, 3, 4]

julia> b = [[1,1,1],[0,0,0]]
2-element Array{Array{Int64,1},1}:
[1, 1, 1]
[0, 0, 0]

julia> aa = [a, a]
2-element Array{Array{Array{Int64,1},1},1}:
[[1, 2, 3], [2, 3, 4]]
[[1, 2, 3], [2, 3, 4]]

julia> ab = [a, b]
2-element Array{Array{Array{Int64,1},1},1}:
[[1, 2, 3], [2, 3, 4]]
[[1, 1, 1], [0, 0, 0]]

1-element Array{Int64,1}:
0