Julia:将数组的向量转换为任意维度的数组 [英] Julia: Converting Vector of Arrays to Array for Arbitrary Dimensions

查看:27
本文介绍了Julia:将数组的向量转换为任意维度的数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用时序测试,我发现使用 push! 增长 Vector{Array{Float64}} 对象比简单地使用 Array{Float64} 对象和 hcatvcat.但是,计算完成后,我需要将生成的对象更改为 Array{Float64} 以进行进一步分析.有没有一种不管尺寸如何都有效的方法?例如,如果我通过

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 Arrays via

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

我可以这样转换:

fill = Array{Int}(size(uFull)...,size(u)...)
for i in eachindex(uFull)
  fill[i,:,:] = uFull[i]
end

但请注意,这要求我知道数组是矩阵(二维).如果它是 3 维的,我需要另一个 :,因此这不适用于任意维度.

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.

推荐答案

这是 Julia 的 自定义数组基础架构 擅长.我认为这里最简单的解决方案是实际制作一个特殊的数组类型来为您进行这种转换:

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:

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

现在只需将您的向量包装在 StackedArray 中,它的行为就像一个 N+1 维数组.这可以扩展并使其更具功能(它可以类似地支持 setindex! 甚至 push!ing 数组以原生连接),但我认为这足以解决您的问题.通过简单地将 uFull 包装在 StackedArray 中,您将获得一个类似于 Array{T, N+1} 的对象.制作一个copy,你就可以得到一个完全密集的Array{T, N+1},而无需自己编写for循环.

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.

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
…

最后,我要注意这里还有另一种解决方案:您可以引入自定义数组类型很快,并制作一个 GrowableArray 在内部将其元素存储为线性 Vector{T},但允许直接推送整个列或数组.

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.

这篇关于Julia:将数组的向量转换为任意维度的数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆