作者:书友8649571 | 来源:互联网 | 2023-06-15 10:04
Usingtimingtests,IfoundthatitsmuchmoreperformanttogrowVector{Array{Float64}}objectsus
Using timing tests, I found that it's much more performant to grow Vector{Array{Float64}}
objects using push!
than it is to simply use an Array{Float64}
object and either hcat
or vcat
. However, after the computation is completed, I need to change the resulting object to an Array{Float64}
for further analysis. Is there a way that works regardless of the dimensions? For example, if I generate the Vector
of Array
s via
使用计时测试,我发现使用push来增加Vector {Array {Float64}}对象的性能要高得多!而不是简单地使用Array {Float64}对象和hcat或vcat。但是,在计算完成后,我需要将结果对象更改为Array {Float64}以进行进一步分析。有没有一种方法可以工作,无论尺寸?例如,如果我通过生成矢量数组
u = [1 2 3 4
1 3 3 4
1 5 6 3
5 2 3 1]
uFull = Vector{Array{Int}}(0)
push!(uFull,u)
for i = 1:10000
push!(uFull,u)
end
I can do the conversion like this:
我可以像这样进行转换:
fill = Array{Int}(size(uFull)...,size(u)...)
for i in eachindex(uFull)
fill[i,:,:] = uFull[i]
end
but notice this requires that I know the arrays are matrices (2-dimensional). If it's 3-dimensional, I would need another :
, and so this doesn't work for arbitrary dimensions.
但请注意,这需要我知道数组是矩阵(二维)。如果它是三维的,我需要另一个:,所以这对任意尺寸都不起作用。
Note that I also need a form of the "inverse transform" (except first indexed by the last index of the full array) in arbitrary dimensions, and I currently have
请注意,我还需要一个“逆变换”的形式(除了第一个由完整数组的最后一个索引索引)在任意维度,我目前有
filla = Vector{Array{Int}}(size(fill)[end])
for i in 1:size(fill)[end]
filla[i] = fill[:,:,i]'
end
I assume the method for the first conversion will likely solve the second as well.
我假设第一次转换的方法也可能解决第二次转换。
2 个解决方案
9
This is the sort of thing that Julia's custom array infrastructure excels at. I think the simplest solution here is to actually make a special array type that does this transformation for you:
这是Julia的定制阵列基础设施擅长的事情。我认为这里最简单的解决方案是实际制作一个特殊的数组类型,为您进行这种转换:
immutable StackedArray{T,N,A} <: AbstractArray{T,N}
data::A # A <: AbstractVector{<:AbstractArray{T,N-1}}
dims::NTuple{N,Int}
end
function StackedArray(vec::AbstractVector)
@assert all(size(vec[1]) == size(v) for v in vec)
StackedArray(vec, (length(vec), size(vec[1])...))
end
StackedArray{T, N}(vec::AbstractVector{T}, dims::NTuple{N}) = StackedArray{eltype(T),N,typeof(vec)}(vec, dims)
Base.size(S::StackedArray) = S.dims
@inline function Base.getindex{T,N}(S::StackedArray{T,N}, I::Vararg{Int,N})
@boundscheck checkbounds(S, I...)
S.data[I[1]][Base.tail(I)...]
end
Now just wrap your vector in a StackedArray and it'll behave like an N+1 dimensional array. This could be expanded and made more featureful (it could similarly support setindex!
or even push!
ing arrays to concatenate natively), but I think that it's sufficient to solve your problem. By simply wrapping uFull
in a StackedArray
you get an object that acts like an Array{T, N+1}
. Make a copy
, and you get exactly a dense Array{T, N+1}
without ever needing to write a for loop yourself.
现在只需将您的矢量包装在StackedArray中,它的行为就像一个N + 1维数组。这可以扩展并使其更具特色(它可以类似地支持setindex!甚至推送数组本地连接),但我认为它足以解决您的问题。通过简单地将uFull包装在StackedArray中,您将获得一个类似于Array {T,N + 1}的对象。制作一个副本,你就可以获得一个密集的数组{T,N + 1}而无需自己编写for循环。
julia> S = StackedArray(uFull)
10001x4x4 StackedArray{Int64,3,Array{Array{Int64,2},1}}:
[:, :, 1] =
1 1 1 5
1 1 1 5
1 1 1 5
…
julia> squeeze(S[1:1, :, :], 1) == u
true
julia> copy(S) # returns a dense Array{T,N}
10001x4x4 Array{Int64,3}:
[:, :, 1] =
1 1 1 5
1 1 1 5
…
Finally, I'll just note that there's another solution here: you could introduce the custom array type sooner, and make a GrowableArray
that internally stores its elements as a linear Vector{T}
, but allows pushing entire columns or arrays directly.
最后,我要注意这里还有另一个解决方案:你可以更快地引入自定义数组类型,并使GrowableArray在内部将其元素存储为线性Vector {T},但允许直接推送整个列或数组。