Заполнение массива массивом работает не так, как я ожидал

#arrays #julia

Вопрос:

Я хочу создать множественный массив, запись в котором является множественным массивом, и хочу вставить в запись один за другим некоторый массив.

Например, я сделал матрицу 2 x 3 с именем arr и попытался заполнить записи [1,1] и [1,2] матрицей 4 x 4, порожденной randn(4,4) .

 arr = fill(Matrix{Float64}[], 2, 3)
push!(arr[1,1],randn(4,4))
push!(arr[1,2],randn(4,4))
println(arr[1,1])
println(arr[1,2])
println(arr[1,3])

 

Однако в результате все записи arr (кроме [1,1] и [1,2]) были заполнены одним и тем же randn(4,4) , а не только [1,1] и [1,2], заполненными randn(4,4) :

 [[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
[[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
[[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
 

Что случилось?
Любая информация будет признательна.

Ответ №1:

Когда вы делаете arr = fill(Matrix{Float64}[], 2, 3) все 6 элементов, они указывают точно в одно и то же место в памяти, потому fill что не делают глубокого копирования — он просто копирует ссылки. В принципе, использование fill , когда первый аргумент является изменяемым, обычно оказывается не очень хорошей идеей.

Следовательно, то, что вы на самом деле хотите, это:

 arr = [Matrix{Float64}[] for i in 1:2, j in 1:3]
 

Теперь каждый из 6 слотов будет иметь свой собственный адрес в памяти.

Ответ №2:

Этот способ создания массива подразумевает, что каждый элемент будет Float64, то есть скаляром. Вам нужно исправить подпись типа. Так, например, вы могли бы сделать

 D = Matrix{Array{Float64, 2}}(undef, 2, 3)
 

если вы хотите, чтобы в качестве элементов были 2-мерные массивы ( Float64,2 это делает это)

а затем распределить

 D[1,1] = rand(4,4)
D[1,2] = rand(4,4)
 

чтобы дать тебе (или, скорее, мне!):

 julia> D[1,1]
4×4 Matrix{Float64}:
 0.210019  0.528594  0.0566622  0.0547953
 0.729212  0.40829   0.816365   0.804139
 0.39524   0.940286  0.976152   0.128008
 0.886597  0.379621  0.153302   0.798803

julia> D[1,2]
4×4 Matrix{Float64}:
 0.640809   0.821668  0.627057  0.382058
 0.532567   0.262311  0.916391  0.200024
 0.0599815  0.17594   0.698521  0.517822
 0.965279   0.804067  0.39408   0.105774