Julia 中二维向量数组的特殊行为

Chu*_*yen 4 julia

我想创建一个二维向量的二维数组(来表示一个向量场)。

我的代码是这样的

N=10
dx=1/(N-1)
dy=1/(N-1)

#initial data
U=fill(zeros(2), (N, N))

for i=1:1:N
    for j=1:1:N
        U[i,j][1]=(i-1)*dx
        U[i,j][2]=(j-1)*dy
    end
end

print(U[5, 7])
Run Code Online (Sandbox Code Playgroud)

结果是[1.0, 1.0],这不是我想要的。我不知道为什么。但是,如果我将代码更改为这样的

N=10
dx=1/(N-1)
dy=1/(N-1)

#initial data
U=fill(zeros(2), (N, N))

for i=1:1:N
    for j=1:1:N
        U[i,j]=[(i-1)*dx, (i-1)*dx]
    end
end

print(U[5, 7])
Run Code Online (Sandbox Code Playgroud)

然后打印出正确的结果,即 [0.4444444444444444, 0.6666666666666666]。那么,发生了什么?

Col*_*ers 5

这种行为是意料之中的。请注意以下事项:

julia> x = fill(zeros(1), 2)
2-element Array{Array{Float64,1},1}:
 [0.0]
 [0.0]

julia> x[1][1] = 5.0
5.0

julia> x[2][1]
5.0
Run Code Online (Sandbox Code Playgroud)

x[2][1]只是通过更改x[1][1]. 您现在大概可以猜到问题所在。您正在使用相同的向量填充矩阵的所有元素。因此,当你改变一个,你就改变了所有。

要获得您想要的行为,您可以像这样构建初始矩阵:

x = [ zeros(2) for n in 1:N, m in 1:N ]
Run Code Online (Sandbox Code Playgroud)

这里的关键点是考虑您fill调用的第一个参数是否是或包含可变参数。如果没有,那么它会像您预期的那样工作,例如fill(0.0, 2). 但是如果它确实包含一个可变对象,那么 的输出fill将包含指向单个可变对象的指针,并且您将获得上面遇到的行为。

请注意,我在这里使用“包含”这个词很重要,因为包含可变对象的不可变对象仍然会导致指向单个可变对象的指针,从而导致您遇到的行为。例如:

struct T1 ; x::Vector{Float64} ; end
T1() = T1(zeros(1))
x = fill(T1(), 2)
x[1].x[1] = 5.0
x[2].x[1]
Run Code Online (Sandbox Code Playgroud)

仍然改变 的第二个元素x