WarpedReality
WarpedReality

Reputation: 89

Return multiple values from a mapped function

Let's say I have a function named trig, which returns two outputs:

function trig(x)
    return(sin(x), cos(x))
end

If I want to evaluate trig over many values, I can use the map function:

julia> out = map(trig, (0:(pi/12):(pi/2)))

out is a 7 element array and in each element, there is a tuple containing two elements:

julia> out
7-element Array{Tuple{Float64,Float64},1}:
(0.0,1.0)
(0.258819,0.965926)
(0.5,0.866025)
(0.707107,0.707107)
(0.866025,0.5)
(0.965926,0.258819)
(1.0,6.12323e-17)

My question is: What is the best way to disentangle my sines and cosines so that I have two arrays with 7 elements each? Is it possible to broadcast trig without creating the superfluous array of tuples and instead directly create the two arrays that I am actually interested in?

For the time being, I am invoking map again in order to extract values from out in order to populate the arrays I want, but I don't think it is the best way to do this:

sines = map(x->x[1], out)
cosines = map(x->x[2], out)

For the purpose of this question, assume trig is a computationally expensive function. So, please do not give me an answer that requires trig to be evaluated more than once.

Upvotes: 5

Views: 1222

Answers (1)

WarpedReality
WarpedReality

Reputation: 89

Thank you tim for sharing your answer to an earlier question that I must have overlooked in my search before asking this one. Before today, I had never heard of the getIndex function, yet it seems that getindex is the function I want, provided that I vectorize it by putting a dot in front:

julia> @time sine_map = map(x->x[1], out)
  0.051494 seconds (13.32 k allocations: 602.941 KB)
7-element Array{Float64,1}:
 0.0
 0.258819
 0.5
 0.707107
 0.866025
 0.965926
 1.0

julia> @time sine_geti = getindex.(out, 1)
  0.029560 seconds (9.24 k allocations: 416.910 KB)
7-element Array{Float64,1}:
 0.0
 0.258819
 0.5
 0.707107
 0.866025
 0.965926
 1.0

julia> @time cosine_map = map(x->x[2], out)
  0.037328 seconds (13.32 k allocations: 602.941 KB)
7-element Array{Float64,1}:
 1.0
 0.965926
 0.866025
 0.707107
 0.5
 0.258819
 6.12323e-17

julia> @time cosey_geti = getindex.(out, 2)
  0.024785 seconds (9.24 k allocations: 416.910 KB)
7-element Array{Float64,1}:
 1.0
 0.965926
 0.866025
 0.707107
 0.5
 0.258819
 6.12323e-17

Reducing the number of allocations by 30% is nothing to sneeze at. Thank you.

I think I am safe making this even more concise:

@time sines, cosines = map(x->getindex.(out, x), 1:2)
  0.062047 seconds (20.81 k allocations: 956.831 KB)
2-element Array{Array{Float64,1},1}:
 [0.0,0.258819,0.5,0.707107,0.866025,0.965926,1.0]
 [1.0,0.965926,0.866025,0.707107,0.5,0.258819,6.12323e-17]

And thank you Colin T Bowers for suggesting that I can define a custom method for trig. I will definitely consider doing this if getindex fails to deliver the performance I want.

Upvotes: 1

Related Questions