Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vectorized splatting

Tags:

julia

I'd like to be able to splat an array of tuples into a function in a vectorized fashion. For example, if I have the following function,

function foo(x, y)
    x + y
end

and the following array of tuples,

args_array = [(1, 2), (3, 4), (5, 6)]

then I could use a list comprehension to obtain the desired result:

julia> [foo(args...) for args in args_array]
3-element Array{Int64,1}:
  3
  7
 11

However, I would like to be able to use the dot vectorization notation for this operation:

julia> foo.(args_array...)
ERROR: MethodError: no method matching foo(::Int64, ::Int64, ::Int64)

But as you can see, that particular syntax doesn't work. Is there a vectorized way to do this?

like image 728
Cameron Bieganek Avatar asked Nov 01 '25 14:11

Cameron Bieganek


2 Answers

foo.(args_array...) doesn't work because it's doing:

foo.((1, 2), (3, 4), (5, 6))
# which is roughly equivalent to
[foo(1,3,5), foo(2,4,6)]

In other words, it's taking each element of args_array as a separate argument and then broadcasting foo over those arguments. You want to broadcast foo over the elements directly. The trouble is that running:

foo.(args_array)
# is roughly equivalent to:
[foo((1,2)), foo((3,4)), foo((5,6))]

In other words, the broadcast syntax is just passing each tuple as a single argument to foo. We can fix that with a simple intermediate function:

julia> bar(args) = foo(args...);

julia> bar.(args_array)
3-element Array{Int64,1}:
  3
  7
 11

Now that's doing what you want! You don't even need to construct the second argument if you don't want to. This is exactly equivalent:

julia> (args->foo(args...)).(args_array)
3-element Array{Int64,1}:
  3
  7
 11

And in fact you can generalize this quite easily:

julia> splat(f) = args -> f(args...);

julia> (splat(foo)).(args_array)
3-element Array{Int64,1}:
  3
  7
 11
like image 53
mbauman Avatar answered Nov 04 '25 03:11

mbauman


You could zip the args_array, which effectively transposes the array of tuples:

julia> collect(zip(args_array...))
2-element Array{Tuple{Int64,Int64,Int64},1}:
 (1, 3, 5)
 (2, 4, 6)

Then you can broadcast foo over the transposed array (actually an iterator) of tuples:

julia> foo.(zip(args_array...)...)
(3, 7, 11)

However, this returns a tuple instead of an array. If you need the return value to be an array, you could use any of the following somewhat cryptic solutions:

julia> foo.(collect.(zip(args_array...))...)
3-element Array{Int64,1}:
  3
  7
 11

julia> collect(foo.(zip(args_array...)...))
3-element Array{Int64,1}:
  3
  7
 11

julia> [foo.(zip(args_array...)...)...]
3-element Array{Int64,1}:
  3
  7
 11
like image 45
Cameron Bieganek Avatar answered Nov 04 '25 04:11

Cameron Bieganek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!