Julia:将数组向量转换为任意维度的数组

时间:2016-05-27 06:59:25

标签: arrays type-conversion julia

使用时序测试,我发现使用Vector{Array{Float64}}增长push!个对象比仅使用Array{Float64}对象和{{1}更高效}或hcat。但是,在计算完成后,我需要将结果对象更改为vcat以进行进一步分析。有没有一种方法可以工作,无论尺寸?例如,如果我通过

生成Array{Float64} Vector s
Array

我可以像这样进行转换:

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

但请注意,这要求我知道数组是矩阵(二维)。如果它是3维的,我需要另一个fill = Array{Int}(size(uFull)...,size(u)...) for i in eachindex(uFull) fill[i,:,:] = uFull[i] end ,因此这对任意维度都不起作用。

请注意,我还需要一种形式的"逆变换" (除了第一个由完整数组的最后一个索引索引)在任意维度,我目前有

:

我认为第一次转换的方法也可能解决第二次转换。

2 个答案:

答案 0 :(得分:9)

这是朱莉娅custom array infrastructure擅长的事情。我认为这里最简单的解决方案是实际制作一个特殊的数组类型,为你做这个转换:

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!数组本地连接),但我认为它足以解决您的问题。只需将uFull包裹在StackedArray中,您就会得到一个像Array{T, N+1}一样的对象。创建一个copy,你就可以得到一个密集的Array{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
…

最后,我只是注意到这里还有另一个解决方案:您可以更快地引入自定义数组类型 ,然后创建一个内部存储它的GrowableArray元素为线性Vector{T},但允许直接推送整个列或数组。

答案 1 :(得分:5)

Matt B.的答案很棒,因为它“模拟”了一个数组,而不必实际创建或存储它。当您可以使用此解决方案时,它可能是您的最佳选择。

但是,在某些情况下,您可能需要创建连接数组(例如,如果您将其传递给某些需要连续内存的C代码)。在这种情况下,您只需调用cat,它是通用的(它可以处理任意维度)。

例如:

u =  [1 2 3 4
      1 3 3 4
      1 5 6 3
      5 2 3 1]
uFull = Vector{typeof(u)}(0)
push!(uFull,u)
for i = 1:10000
  push!(uFull,u)
end
ucat = cat(ndims(eltype(uFull))+1, uFull)

我冒昧地对您的代码进行了一次重要更改:uFull = Vector{typeof(u)}(0)因为它确保存储在Vector容器中的对象具有具体类型。 Array{Int}实际上是一种抽象类型,因为您还需要指定维度(Array{Int,2})。