2017-05-29 135 views
2

比方说,我有一个名为三角函数,它返回两个输出:从映射函数返回多个值

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

如果我想对很多值来评价制动,我可以使用地图功能:

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

出是一个7元件阵列和中的每个元素,存在包含两个元素的元组:

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) 

我的曲estion是:什么是解开我的正弦和余弦的最好方法,以便我有两个每个都有7个元素的数组?是否可以在不创建多余元组数组的情况下广播trig,而是直接创建两个实际感兴趣的数组?

暂时,我才能从出以填充我想要的阵列中提取值再次调用地图,但我不认为这是做到这一点的最好办法:

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

对于这个问题,假定trig是一个计算量很大的函数。所以,请不要给我一个要求trig多次评估的答案。

+0

我不认为有什么办法可以在没有重新分配的情况下做到这一点,因为例如在内存中“0.0”和“0.258819”并不相邻(“1.0”在两者之间)。要看到这个,使用'reinterpret(Float64,out,(2,7))',它没有开销,但是请注意'sines'是输出矩阵的第一行,'cosines'是第二行,并且由于数组是列主要的顺序,因此将'sines'提取为'Vector' *必须*触发重新分配。换句话说,我怀疑'map'将会像解决这个问题一样好... –

+1

或者,只需为'AbstractVector'输入大小写的'trig'提供自己的方法定义,并将调用的输出分配给问题中的trig方法明确地指向两个向量。有可能是一个聪明的单线程来做到这一点,但我不能看到它从我的头顶(我的版本将有一个预分配线和显式循环) –

+1

也参见https://stackoverflow.com/q/44010033和https://stackoverflow.com/q/41183481/6172490。 – tim

回答

1

谢谢你提出这个问题之前,我在搜索中一定忽略了一个早期问题的答案。在今天之前,我从来没有听说过的getIndex的功能,但它似乎getindex是我想要的功能,前提是我向量化它通过把一个点在前面:

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 

减少分配的数量由30%没什么可以打喷嚏的。谢谢。

我想我是安全的使这个更简洁:

@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] 

谢谢你科林牛逼鲍尔斯的暗示我可以定义三角函数的自定义方法。如果getindex无法提供我想要的效果,我肯定会考虑这样做。

+0

尝试'sines,余弦=地图(收集,拉链(出...))''也。虽然可能效率不高。 –

+1

请勿在全球范围内进行基准测试。将代码封装在一个函数中,或者使用'BenchmarkTools'和'@btime getindex。($ out,1)'代替。 – tim