推!覆盖朱莉娅的早期元素

时间:2018-03-22 14:48:27

标签: arrays julia

在朱莉娅(0.6.2),推!偶尔会覆盖推送最后一个元素的所有先前元素。这是一段出现的代码;最后,out由相同的条目组成。

using Distributions
l = [(0, 10, 1, [1.1; 2.2], [1/3; 2/3], 4)];
out = Array{Float64}[ ]; # output
entry = zeros(Float64,3);
for i = 1:length(l)
    row = l[i];
    startingtime = row[1];
    finishingtime = row[2];
    node = row[3];
    sizelist = row[4];
    sizedistr = row[5];
    density = row[6];
    t = startingtime;
    deltat = rand(Exponential(1/density));
    while t + deltat < finishingtime
        t = t + deltat;
        filetype = rand(Categorical(sizedistr));
        size = sizelist[filetype];
        entry[1] = t; entry[2] = node; entry[3] = size;
        print(entry,"\n");
        push!(out, entry);
        deltat = rand(Exponential(density));
    end;
end;

out

我有点担心重复性,因为在其他类似的情况下,推!工作得很好。那么......这是一个真正的错误吗?或者有一个简单的解决方案吗?提前谢谢!

编辑:好的,澄清:通过再现性,我的意思是在许多其他情况下,推!工作得很好,我没有看到它的特定模式。甚至可能发生在另一台计算机上,此代码运行良好。我不知道。但由于某种原因,对我来说,上面的代码不能正常工作:对于每次运行,它会产生一个由相同条目组成的out。这是一个输出:

[0.175033, 1.0, 2.2]
[0.24153, 1.0, 2.2]
[4.95478, 1.0, 2.2]
[7.46299, 1.0, 2.2]
Array{Float64,N} where N[[7.46299, 1.0, 2.2], [7.46299, 1.0, 2.2], [7.46299, 1.0, 2.2], [7.46299, 1.0, 2.2]]

打印输出还显示生成时条目实际上是不同的,但它们会在push!之后重写。这种现象也发生在其他一些不含随机性的代码中,但它太长了(我甚至不知道哪些部分与bug有关,所以我甚至无法减少它)所以我尽量避免在这里包含它。

2 个答案:

答案 0 :(得分:1)

这与随机性或push!无关。您只需将同一个数组(实际上是一个指针)推送到out,同时每次更改其内容:

julia> entry = zeros(Float64, 3)
3-element Array{Float64,1}:
 0.0
 0.0
 0.0

julia> out = Array{Float64}[]
0-element Array{Array{Float64,N} where N,1}

julia> for t = 1:3
           entry[1], entry[2], entry[3] = rand(), rand(), rand()
           println(entry)
           push!(out, entry)
           println(out)
       end
[0.913257, 0.413237, 0.612766]
Array{Float64,N} where N[[0.913257, 0.413237, 0.612766]]
[0.00247971, 0.0204771, 0.891242]
Array{Float64,N} where N[[0.00247971, 0.0204771, 0.891242], [0.00247971, 0.0204771, 0.891242]]
[0.847745, 0.742295, 0.0260808]
Array{Float64,N} where N[[0.847745, 0.742295, 0.0260808], [0.847745, 0.742295, 0.0260808], [0.847745, 0.742295, 0.0260808]]

julia> pointer(out[1])
Ptr{Float64} @0x00007f7e0abfaf20

julia> pointer(out[2])
Ptr{Float64} @0x00007f7e0abfaf20

看到了吗?基本上,每次更改相同的entry,最后在out中最终都会使用相同的引用三次。

如何避免?只需在循环中指定entry

julia> out = Array{Float64}[]
0-element Array{Array{Float64,N} where N,1}

julia> for t = 1:3
           entry = rand(3)
           println(entry)
           push!(out, entry)
           println(out)
       end
[0.141818, 0.743078, 0.760137]
Array{Float64,N} where N[[0.141818, 0.743078, 0.760137]]
[0.625746, 0.558617, 0.633356]
Array{Float64,N} where N[[0.141818, 0.743078, 0.760137], [0.625746, 0.558617, 0.633356]]
[0.337548, 0.55715, 0.78439]
Array{Float64,N} where N[[0.141818, 0.743078, 0.760137], [0.625746, 0.558617, 0.633356], [0.337548, 0.55715, 0.78439]]

然后你可以完全删除外部声明。你不能避免使用3个单独的entry,因为你真的需要那么多的分配,如果你想要它们不同......

哦,不需要那些分号。如果那是你的动力,朱莉娅不会自动打印任何东西,比如Matlab。

答案 1 :(得分:1)

在循环的每次迭代中,您将相同的 entry向量附加到out。在每次迭代中,您只是变异entry,有效地为最终out数组中的所有实例进行变异。

使用更简单的代码块更容易看到:

julia> entry = zeros(3);
julia> out = [];
julia> for i in 1:3
         entry[1] = rand()
         @show entry
         push!(out, entry)
       end
entry = [0.580382, 0.0, 0.0]
entry = [0.210324, 0.0, 0.0]
entry = [0.658214, 0.0, 0.0]
julia> out
3-element Array{Any,1}:
 [0.658214, 0.0, 0.0]
 [0.658214, 0.0, 0.0]
 [0.658214, 0.0, 0.0]

最终的out包含看似重复的元素,因为它中的每个元素都是你在循环中修改的相同的向量:

julia> out[1] === out[2] === out[3]
true

如果您希望out中的每个条目都是一个单独的向量,那么您需要在每次迭代时构造一个新的entry或在copy()之前将其推入{{1} }}。例如:

out

如果您不想julia> out = []; julia> for i in 1:3 entry[1] = rand() @show entry push!(out, copy(entry)) end entry = [0.992697, 0.0, 0.0] entry = [0.0971598, 0.0, 0.0] entry = [0.918921, 0.0, 0.0] julia> out 3-element Array{Any,1}: [0.992697, 0.0, 0.0] [0.0971598, 0.0, 0.0] [0.918921, 0.0, 0.0] 而不是:

copy()

只是做:

entry[1] = t; entry[2] = node; entry[3] = size;
print(entry,"\n");
push!(out, entry);