在Julia中定义任意维度的多维数组

5

背景

这个问题与这个问题有关。

在Julia中,我想要创建一个5 x 5的二维数组,其中(i,j)元素像这样具有[i,j]

5×5 Matrix{Vector{Int64}}:
 [1, 1]  [1, 2]  [1, 3]  [1, 4]  [1, 5]
 [2, 1]  [2, 2]  [2, 3]  [2, 4]  [2, 5]
 [3, 1]  [3, 2]  [3, 3]  [3, 4]  [3, 5]
 [4, 1]  [4, 2]  [4, 3]  [4, 4]  [4, 5]
 [5, 1]  [5, 2]  [5, 3]  [5, 4]  [5, 5]

我尝试使用数组推导实现此操作:
N = 5
L_2 = [[x1,x2] for x1 = 1:N, x2 = 1:N]

我想做什么

我想将这个定义推广到任意维度D

L_1 = [[x1] for x1 = 1:N] # 1-dimensional
L_2 = [[x1,x2] for x1 = 1:N, x2 = 1:N] # 2-dimensional
L_3 = [[x1,x2,x3] for x1 = 1:N, x2 = 1:N,x3 = 1:N] # 3-dimensional
...

#L_D = ??? # D-dimensional

我应该怎样定义?

不使用数组推导也可以。

非常感谢任何相关信息。


2
那么你想用这个做什么?如果是为了索引到先前存在的N维数组X中,那么你可以直接使用CartesianIndices(X)。这适用于任何维度和大小。 - DNF
@DNF 换句话说,CartesianIndices(X)CartesianIndices(size(X)) 的作用是相同的。如果 X 不存在且您需要一个 NxNxNx... 的索引数组,则需要进行所有这些数字计算。 - BatWannaBe
2个回答

5
你可以将我在另一个答案中发布的vcat方法进行概括,方法如下:
julia> lattice(N, D) = vcat.((reshape(1:N, ntuple(j -> j == i ? N : 1, D)) for i in 1:D)...)
lattice (generic function with 1 method)

julia> lattice(2, 1)
2-element Vector{Vector{Int64}}:
 [1]
 [2]

julia> lattice(2, 2)
2×2 Matrix{Vector{Int64}}:
 [1, 1]  [1, 2]
 [2, 1]  [2, 2]

julia> lattice(2, 3)
2×2×2 Array{Vector{Int64}, 3}:
[:, :, 1] =
 [1, 1, 1]  [1, 2, 1]
 [2, 1, 1]  [2, 2, 1]

[:, :, 2] =
 [1, 1, 2]  [1, 2, 2]
 [2, 1, 2]  [2, 2, 2]

julia> lattice(2, 4)
2×2×2×2 Array{Vector{Int64}, 4}:
[:, :, 1, 1] =
 [1, 1, 1, 1]  [1, 2, 1, 1]
 [2, 1, 1, 1]  [2, 2, 1, 1]

[:, :, 2, 1] =
 [1, 1, 2, 1]  [1, 2, 2, 1]
 [2, 1, 2, 1]  [2, 2, 2, 1]

[:, :, 1, 2] =
 [1, 1, 1, 2]  [1, 2, 1, 2]
 [2, 1, 1, 2]  [2, 2, 1, 2]

[:, :, 2, 2] =
 [1, 1, 2, 2]  [1, 2, 2, 2]
 [2, 1, 2, 2]  [2, 2, 2, 2]

julia> lattice(2, 5)
2×2×2×2×2 Array{Vector{Int64}, 5}:
[:, :, 1, 1, 1] =
 [1, 1, 1, 1, 1]  [1, 2, 1, 1, 1]
 [2, 1, 1, 1, 1]  [2, 2, 1, 1, 1]

[:, :, 2, 1, 1] =
 [1, 1, 2, 1, 1]  [1, 2, 2, 1, 1]
 [2, 1, 2, 1, 1]  [2, 2, 2, 1, 1]

[:, :, 1, 2, 1] =
 [1, 1, 1, 2, 1]  [1, 2, 1, 2, 1]
 [2, 1, 1, 2, 1]  [2, 2, 1, 2, 1]

[:, :, 2, 2, 1] =
 [1, 1, 2, 2, 1]  [1, 2, 2, 2, 1]
 [2, 1, 2, 2, 1]  [2, 2, 2, 2, 1]

[:, :, 1, 1, 2] =
 [1, 1, 1, 1, 2]  [1, 2, 1, 1, 2]
 [2, 1, 1, 1, 2]  [2, 2, 1, 1, 2]

[:, :, 2, 1, 2] =
 [1, 1, 2, 1, 2]  [1, 2, 2, 1, 2]
 [2, 1, 2, 1, 2]  [2, 2, 2, 1, 2]

[:, :, 1, 2, 2] =
 [1, 1, 1, 2, 2]  [1, 2, 1, 2, 2]
 [2, 1, 1, 2, 2]  [2, 2, 1, 2, 2]

[:, :, 2, 2, 2] =
 [1, 1, 2, 2, 2]  [1, 2, 2, 2, 2]
 [2, 1, 2, 2, 2]  [2, 2, 2, 2, 2]

1
感谢您展示了许多例子,使我易于理解。 - ten

5

看起来你并不需要使用CartesianIndices,但是为了记录,CartesianIndices可以接受任何Int元组(更准确地说是Dims或NTuple {N, Int} where N)表示数组的大小。例如一个5x5的数组可以用CartesianIndices((5, 5))表示,一个2x8x3的数组可以用CartesianIndices((2, 8, 3))表示,等等。你可以通过使用NtotheD(N, D) = ntuple(i -> N, D)来快速生成一个表示D维大小的NxNxNx... 元组。


谢谢。我想在我的项目中使用CartesianIndices。但是,将来我需要为格点的每个点使用Float64的索引。将Int64转换为Float64容易吗? - ten
1
将Int64转换为Float64非常容易,但您是不是想问相反的情况?我必须提醒您,CartesianIndex {N}是仅围绕NTuple {N,Int}的包装器,因此NTuple {N,Float64}无法使用。如果您像A[3.0]这样索引,则getindex方法需要将3.0转换为3。将Float64转换为Int64有点棘手,因为如果您执行A [3.1],则必须决定如何四舍五入到最近的整数。 - BatWannaBe
我未来想要做的是制作一个“单位”格子,它有5 x 5个点并且被等距分割。→ 单位格子: 0.2、0.4、0.6、0.8、1.0。这需要使用CartesianIndices吗? - ten
可能。CartesianIndex{N} 只能包含Int,但您可以根据需要从Int计算出Float64。我能想到的是,您可以创建一个子类型为AbstractArray(请参见Julia文档中的Interfaces页面)并简单包装CartesianIndices的结构体。该结构体的getindex将索引CartesianIndices以获取CartesianIndex,将Int转换为Float64值,并返回它们。与CartesianIndices一样,晶格值是按需生成的,在堆上不需要提前分配任何内存(尽管您可以collect它以一次性生成所有值)。 - BatWannaBe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接